I’ve noticed that how things get passed between numba and python can significantly effect the runtime. For example consider the following three ways of passing parameters into an njit function:
from numba import njit, f8 from numba.types import unicode_type, Tuple from numba.typed import List import timeit N=1000 def time_ms(f): f() #warm start return " %0.6f ms" % (1000.0*(timeit.timeit(f, number=N)/float(N))) @njit def separate(f1,f2,f3,f4, s1,s2,s3,s4): return f1 + f2 + f4 + f4 + len(s1) + len(s2) + len(s3) + len(s4) @njit def together(t): f1,f2,f3,f4,s1,s2,s3,s4 = t return f1 + f2 + f4 + f4 + len(s1) + len(s2) + len(s3) + len(s4) @njit def from_list(l): f1,f2,f3,f4,s1,s2,s3,s4 = l return f1 + f2 + f4 + f4 + len(s1) + len(s2) + len(s3) + len(s4) tup = (1,2,3,4,"A","BB", "CC", "DDD") def s(): separate(1,2,3,4,"A","BB","CC","DDD") def t(): together(tup) lst = List.empty_list(Tuple((f8,f8,f8,f8,unicode_type,unicode_type,unicode_type,unicode_type))) lst.append(tup) def l(): from_list(lst) print(time_ms(s)) # 0.006556 ms print(time_ms(t)) # 0.040448 ms print(time_ms(l)) # 0.001097 ms
Somewhat counter-intuitively wrapping the arguments in a tuple in a typed list works best. I assume this is because the actual guts of List() doesn’t get boxed/unboxed when you just pass it between numba and python. My use case involves moving a lot of different Dicts between python and numba. Most of the time I don’t need to read into these Dicts on the python side, but I do need to pass them around. It would be nice to have some kind of custom context object that was just like a struct or tuple that I could pass into numba functions and change as needed, but that doesn’t unbox into a native type.
My question is is there any straightforward way to make this sort of custom type that I can use to just pass around my dictionaries and stuff without any substantial boxing/unboxing. Something that can be AOT-compiled is preferable. Haven’t had much luck with jitclasses and structrefs, they don’t seem to vibe well with AOT compilation.