Numba技术疑问:被调用函数是否自动生效?numpy函数为何更慢?
Numba相关问题解答
1. Numba是否会自动将@jit装饰器应用于被其他已装饰函数调用的函数?
不会的,Numba可不会自动把装饰器“扩散”到被调用的函数上。只有直接被@jit(或@njit)装饰的函数才会被Numba编译成高效的机器码。如果你的已装饰函数调用了一个没加装饰器的普通Python函数,那这个被调用的函数还是会按Python解释器的方式运行,完全享受不到Numba的加速。
要是想让被调用的函数也获得Numba的优化,你有两个选择:
- 给这个被调用的函数也加上@jit装饰器;
- 如果用的是@njit(纯机器码模式,不回退到Python解释器),那被调用的函数要么是Numba原生支持的内置/NumPy函数,要么必须也是被Numba编译过的函数,不然会报错。
2. 为啥直接调用np.exp(-1j*mat)比调用自定义cexp函数慢?
这个问题的核心在于Numba的内联优化和运算链的处理方式,咱们结合你的代码来看:
你的代码片段:
from numba import jit import numpy as np @jit def dostuff(mat): ''' Do stuff with the matrix ''' return np.exp(-1j*mat) @jit def dostuff_fast(mat): ''' Do stuff with the matrix ''' return cexp(-1j*mat) @jit def cexp(mat): return np.exp(mat)
关键原因:
- 函数内联优化:因为
cexp也被@jit装饰了,当dostuff_fast调用它的时候,Numba会自动把cexp的代码内联到dostuff_fast中——相当于把np.exp(mat)直接写到dostuff_fast里,省去了一次函数调用的开销,同时能让编译器对整个运算做更深度的优化。 - 运算链的优化差异:在
dostuff里,你直接写np.exp(-1j*mat),Numba需要先计算-1j*mat生成一个临时复数矩阵,再把这个临时矩阵传给np.exp。而内联后的dostuff_fast版本,编译器可以把“复数乘法+指数运算”的整个流程合并优化,避免了临时数组的创建和拷贝,这会节省不少时间,尤其是处理大型矩阵的时候。 - Numba对NumPy复数函数的处理细节:虽然Numba支持大部分NumPy函数,但直接在参数里做复合运算(比如
-1j*mat作为np.exp的参数)时,Numba的优化器可能没法像处理拆分后的运算那样彻底。而通过自定义函数拆分后,Numba能更高效地编译每一步操作。
简单来说,自定义cexp让Numba有机会把整个运算流程揉在一起优化,而直接写复合调用的话,优化空间被限制了,自然速度就慢了。
内容的提问来源于stack exchange,提问作者Forrest Thumb
相关产品推荐
相关产品推荐

