版本 0.59.0 (2024年1月31日)

这是 Numba 的一个主要版本。Numba 现在支持 Python 3.12,以下是所有值得关注的项目的摘要。

要点

支持 Python 3.12

此版本的突出功能是 Numba 正式支持 Python 3.12。

请注意,在此版本中(对于 Python 3.12)暂时禁用了性能分析支持,并且在开发过程中已发现了一些已知问题。Numba 团队正在积极解决这些问题。请参阅相应的问题页面(Numba #9289Numba #9291),以获取正在进行的问题列表和进展更新。

(PR-#9246)

将最小支持的 Python 版本移至 3.9。

已移除对 Python 3.8 的支持,Numba 的最小支持 Python 版本现在是 Python 3.9。

(PR-#9310)

新功能

添加对 ufunc 属性和 reduce 的支持

添加了对 ufunc.reduce 和大多数 ufunc 属性的支持。

(PR-#9123)

添加配置变量以启用/禁用 llvmlite 内存管理器

添加了一个配置变量,用于强制启用或禁用 llvmlite 内存管理器。

(PR-#9341)

改进

TargetLibraryInfo 通道添加到 CPU LLVM 流水线。

TargetLibraryInfo 通道确保在调用简化期间进行的优化适合目标,否则目标被假定为 Linux,代码将被优化以生成例如在 Windows 上不存在的数学符号。历史上,这个问题通过使用 Numba 内部库承载封装符号来避免,但这可能会损害性能。由于此更改,Numba 内部库更小,并且在使用 exp2log2 函数的代码中增加了优化机会。

(PR-#9336)

Numba 弃用警告类现在是内置警告类的子类

为了帮助用户管理和抑制 Numba 的弃用警告,NumbaDeprecationWarningNumbaPendingDeprecationWarning 类现在分别是内置 DeprecationWarningPendingDeprecationWarning 的子类。因此,对 DeprecationWarningPendingDeprecationWarning 的警告过滤器将适用于 Numba 弃用警告。

(PR-#9347)

NumPy 支持

添加了对 np.indices() 函数的支持。

添加了对 numpy.indices() 的支持。

(PR-#9126)

添加了对 np.polynomial.polynomial.Polynomial 类的支持。

添加了对来自 np.polynomial.polynomial 包的 Polynomial 类的支持。

(PR-#9140)

添加了对 np.polynomial.polyutils.as_series() 函数以及 np.polynomial.polynomial 中的 polydiv()polyint()polyval() 函数的支持。

添加了对 np.polynomial.polyutils.as_series()np.polynomial.polynomial.polydiv()np.polynomial.polynomial.polyint()(仅前 2 个参数)、np.polynomial.polynomial.polyval()(仅前 2 个参数)的支持。

(PR-#9141)

添加了对 np.unwrap() 函数的支持。

添加了对 numpy.unwrap() 的支持。axis 参数仅在其值等于 -1 时受支持。

(PR-#9154)

添加了对检查 dtypes 是否相等的支持。

添加了对检查两个 dtype 对象是否相等的支持,例如 assert X.dtype == np.dtype(np.float64)

(PR-#9249)

CUDA API 变更

添加了对使用 C ABI 编译设备函数的支持

通过 compile_ptx() API 添加了对使用 C ABI 编译设备函数的支持,以便于与 CUDA C/C++ 和其他语言进行互操作。

(PR-#9223)

使 grid() 和 gridsize() 使用 64 位整数

cuda.grid()cuda.gridsize() 现在使用 64 位整数,因此当网格包含超过 2 ** 31 个线程时,它们不再溢出。

(PR-#9235)

通过实现已使用列表防止内核被丢弃

内核在使用 nvJitLink 编译和链接时不再被丢弃,因为它们已被添加到 @"llvm.used" 列表中。

(PR-#9267)

支持 Windows CUDA 12.0 工具包 conda 包

Windows 上 CUDA 工具包 12.0 conda 包中使用的库路径已添加到检测 CUDA 库时使用的搜索路径中。

(PR-#9279)

性能改进和变更

IR 复制速度的改进

FunctionIR 的深度复制进行了改进。在一种情况下,InlineInlineables 通道的速度提高了 3 倍。

(PR-#9245)

Bug 修复

动态分配 Parfor 调度

此 PR 修复了并行区域在循环中多次执行的问题。之前的代码使用 alloca 在栈上分配 parfor 调度,但如果循环中有很多这样的 parfors,栈就会溢出。新代码在并行区域前后分别调用 Numba 并行运行时进行一对分配/释放操作。目前,这些调用重定向到 malloc/free,尽管其他机制如池化也是可能的,并可能在以后实现。此 PR 还会在 prange 循环未转换为 parfor 的情况下添加警告。如果循环中存在异常控制流,则可能会发生这种情况。这些问题相关,因为原始问题中的 prange 循环未转换为 parfor,因此 prange 主体内的所有 parfors 都在并行运行,并且每次都添加到栈中。

(PR-#9048)

支持 @guvectorize 函数中的多个输出

此 PR 修复了 Numba #9058,现在可以调用具有多个输出的 guvectorize。

(PR-#9049)

修复了 PythonAPI.callNone 参数的处理。

修复了当 args=None 传递给 PythonAPI.call 时导致的段错误。

(PR-#9089)

修复 PHI 节点中字面量值的传播。

修复了字面量传播通道中的一个 bug,该 bug 导致 PHI 节点可能被错误地替换为常量。

(PR-#9144)

numpy.digitize 实现行为与 numpy 对齐

更新了 numpy.digitize 的实现,使其在更广泛的情况下(包括提供的 bin 实际上不是单调的情况)与 numpy 的行为保持一致。

(PR-#9169)

numpy.searchsortednumpy.sort 行为更新

  • numpy.searchsorted 实现已更新,以在更广泛的使用场景中(包括提供的数组 a 实际上未正确排序的情况)生成与 numpy 相同的输出。

  • numpy.searchsorted 实现修复了 side='right' 且提供的数组 a 包含 NaN 的情况下的 bug。

  • numpy.searchsorted 实现已扩展以支持复数输入。

  • numpy.sort(和 array.sort)实现已扩展以支持复数数据的排序。

(PR-#9189)

修复 SSA 以考虑其使用未被定义支配的变量

修复了一个 SSA 问题,使得条件定义的变量将接收一个 phi 节点,表明存在变量未定义的路径。这会影响依赖 SSA 行为的扩展代码。

(PR-#9242)

修复 prange 中的 RecursionError

修复了使用 prange 的某些循环模式导致编译器中出现 RecursionError 的问题。此类循环的一个示例如下所示。该问题将导致编译器陷入无限递归循环,尝试确定 var1var2 的定义。该模式涉及在 if-else 树中定义变量,并且并非所有分支都定义变量。

for i in prange(N):
    for j in inner:
        if cond1:
            var1 = ...
        elif cond2:
            var1, var2 = ...

        elif cond3:
            pass

        if cond4:
            use(var1)
            use(var2)

(PR-#9244)

支持 ufunc.reduce 中的负轴

修复了 ufunc.reduce 中一个 bug,以正确处理负轴值。

(PR-#9296)

修复 Python 3.12 中的 parfor 约简问题。

parfor 约简代码对它发现的语句顺序有一些预期,这些预期基于 Numba 以前版本生成的代码。在 Python 3.12 中,一个曾经跟随约简运算符语句(例如二元操作)的赋值现在被移到了它自己的基本块中。此更改重新排序了发现的约简节点集,使得此赋值紧随约简运算符,就像 Numba 以前的版本中一样。这仅影响内部 parfor 约简代码,实际上不改变 Numba IR。

(PR-#9334)

变更

使测试列表不调用 CPU 编译。

Numba 的测试列表命令 python -m numba.runtests -l 历史上由于测试套件中某些测试函数的声明方式而触发 CPU 目标编译。现在已更改为在测试列表时不再调用 CPU 目标编译器,并添加了一个测试以确保这种情况保持不变。

(PR-#9309)

由于 Python 3.12 推导式中的变量遮蔽导致的语义差异

Python 3.12 引入了一个新的字节码 LOAD_FAST_AND_CLEAR,它仅用于推导式。它具有 Numba 无法建模的动态语义。

例如,

def foo():
    if False:
        x = 1
    [x for x in (1,)]
    return x  # This return uses undefined variable

在 return 语句处变量 x 是未定义的。Numba 不会引发 UnboundLocalError,而是在编译时如果使用了未定义的变量则会引发 TypingError

但是,Numba 并非总能检测到未定义的变量。

例如,

def foo(a):
    [x for x in (0,)]
    if a:
        x = 3 + a
    x += 10
    return x

调用 foo(0) 返回 10 而不是引发 UnboundLocalError。这是因为 Numba 在运行时不跟踪变量的生命周期。返回值是 0 + 10,因为 Numba 会将未定义的变量零初始化。

(PR-#9315)

重构并移除遗留 API/测试内部机制。

为了通过减少调用编译的方式来帮助日常维护,已移除了许多内部使用的函数,特别是

  • numba.core.compiler.compile_isolated 已移除。

  • numba.tests.support.TestCase::run_nullary_func 已移除。

  • numba.tests.support.CompilationCache 已移除。

此外,已从 numba.core.registry.CPUTarget 中移除了“嵌套上下文”的概念以及实现细节。目标扩展(那些使用 numba.core.target_extension 中的 API 将 Numba 支持扩展到自定义/合成硬件的扩展)的维护者应注意,如果自定义目标的 TargetDescriptor 中存在,也可以将其从目标扩展实现中删除。即,可以将 nested_context 方法和相关的实现细节从自定义目标的 TargetDescriptor 中直接删除。

此外,在重构过程中发现了一个关于记录数组类型化的 bug。结果表明,两个仅在可变性上不同的记录类型可能会别名,现在已修复此问题。

(PR-#9330)

弃用

显式设置 NUMBA_CAPTURED_ERRORS=old_style 将引发弃用警告

根据旧式错误捕获的弃用计划,显式设置 NUMBA_CAPTURED_ERRORS=old_style 将引发弃用警告。此版本是最后一个使用“old_style”作为默认值的版本。详细信息记录在 https://numba.readthedocs.cn/en/stable/reference/deprecation.html#deprecation-of-old-style-numba-captured-errors

(PR-#9346)

已过期的弃用

对象模式回退支持已移除。

根据 Numba 0.59.0 的弃用计划,已从所有 Numba jit 系列装饰器中移除了“对象模式回退”支持。此外,nopython 关键字参数的默认值已更改为 True,这意味着所有 Numba jit 系列装饰函数现在将默认在 nopython 模式下编译。

(PR-#9352)

移除弃用的 API @numba.generated_jit

根据 0.59.0 的弃用计划,已移除对 @numba.generated_jit 的支持。建议使用 @numba.extending.overload 和高级扩展 API 作为替代。

(PR-#9353)

Pull 请求: