Can a "nogil" configged in the outter-most function applys to all the routines called inside?

When a function is jitted with option nogil=True, will all the routines it calls automatically release the gil?

from numba import njit
from numba.experimental import jitclass

@njit
def inner(...) ...  # not explicitly releasing gil here

@jitclass
class Foo:  # cannot config gil here
    def bar(self)...

@njit(nogil=True)
def outter(...):
    # Q: Will the gil holds during the following calls?
    inner(...)    
    Foo().bar() ...

A question very similar to https://numba.discourse.group/t/nogil-with-jitclass/394

Late reply, but for future reference: nogil does release the gil for every nested function. I was able to get a race condition with the following code:

from concurrent.futures import ThreadPoolExecutor

import numpy as np
from numba import int64, njit
from numba.experimental import jitclass


@jitclass([("count", int64)])
class Counter:
    def __init__(self):
        self.count = 0

    def add(self):
        # Filler to keep cpu busy
        x = np.random.random_sample(100000)
        y = np.sqrt(x)

        self.count += 1


@njit(nogil=True)
def add_count(counter: Counter):
    counter.add()


def main():
    num_runs = 5
    for run in range(num_runs):
        counter = Counter()

        num_counts = 100000
        with ThreadPoolExecutor() as pool:
            for _ in range(num_counts):
                pool.submit(add_count, counter)

        print(f"Run {run}: {counter.count}")


if __name__ == "__main__":
    main()

Results:

Run 0: 99999
Run 1: 100000
Run 2: 100000
Run 3: 100000
Run 4: 99999

This proves the GIL is not active, because it would prevent this race condition. I was also able to get 100% cpu usage with the filler code.

1 Like