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() ...
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.