与 Python 语义的偏差
边界检查
默认情况下,Numba 编译函数中访问数组越界索引时,不会引发 IndexError
,而是返回无效值或导致访问冲突错误(因为它正在读取无效内存位置)。可以通过 jit 装饰器的 boundscheck 选项为特定函数启用边界检查。此外,可以将 NUMBA_BOUNDSCHECK
设置为 0 或 1,以全局覆盖此标志。
注意
边界检查会降低典型函数的运行速度,因此建议仅将此标志用于调试目的。
异常和内存分配
由于当前编译器在处理异常时的限制,在引发异常的函数内分配的内存(几乎总是 NumPy 数组)将泄漏。这是一个已知问题,未来会得到修复,但在此期间,最好在也可能引发异常的函数之外进行内存分配。
整数宽度
虽然 Python 具有任意大小的整数,但 Numba 编译函数中的整数通过类型推断获得固定大小(通常是机器整数的大小)。这意味着算术运算可能会回绕、产生未定义的结果或溢出。
如果需要对整数宽度进行细粒度控制,可以通过显式类型规范覆盖类型推断。
另请参阅
布尔反转
对 Python 布尔值调用按位补码运算符(~
运算符)会返回一个整数,而对 Numpy 布尔值使用相同的运算符会返回另一个布尔值。
>>> ~True
-2
>>> ~np.bool_(True)
False
Numba 遵循 Numpy 的语义。
全局变量和闭包变量
在nopython 模式下,全局变量和闭包变量被 Numba 冻结:Numba 编译的函数看到的是这些变量在函数编译时的值。此外,无法从函数内部更改它们的值。
Numba 可能或可能不复制编译函数中引用的全局变量。小的全局数组会被复制,以进行潜在的编译器优化,并假定其不可变性。但是,大的全局数组不会被复制,以节省内存。“小”和“大”的定义可能会改变。
变量的零初始化
Numba 在运行时不跟踪变量的活跃性。为了实现简单,所有变量都进行零初始化。示例
from numba import njit
@njit
def foo():
for i in range(0):
pass
print(i) # will print 0 and not raise UnboundLocalError
foo()