当我有一个函数在不更改类型的情况下递归调用自己,但处理一个大对象(作为参数传递(时。。。这在幕后是如何运作的?
我的函数(很小,但调用次数很多(是在第一次调用时及时编译的,但尚未完成(因为递归(,还是只有在函数的第一次调用完成时才完成编译?
例如
@njit
def myfct(large_object):
a, tail_condition = do_things_1(intermediate_result)
if tail_condition == True:
return a
intermediate_result = myfct(large_object)
b = do_things_2(a, intermediate_result)
return b
final_result = myfct(ref_to_large_object)
myfct
是什么时候编译的?它是在第6行第二次被调用之前就已经编译过了,还是只有在我得到final_result
并且一切都已经完成时才编译?如果是后一种情况,我该怎么避免呢?
每个签名编译一次函数。如果您没有提供显式签名,则会在第一次使用每个签名时对其进行编译:
@nb.njit
def f(n):
return n * f(n-1) if n > 1 else 1
f(4) # Compiled here
f(5) # Already compiled
f(5.1) # Compiled again
如果提供显式签名,则在声明时编译函数:
@nb.njit([nb.int32(nb.int32)])
def f(n):
return n * f(n-1) if n > 1 else 1
f(5) # Already compiled
f(5.1) # Crashes. No attempt to compile an additional signature.
提供多个显式签名:
@nb.njit([nb.int32(nb.int32), nb.float64(nb.float64)])
def f(n):
return n * f(n-1) if n > 1 else 1
f(5) # Already compiled
f(5.1) # Already compiled
您可以通过在numba.core.dispatcher.Dispatcher.compile()
中放置断点来自行检查。