弃用通知
本节包含关于弃用行为、功能和API的信息,这些行为、功能和API已经变得不受欢迎/过时。任何关于它们弃用时间表的信息以及更改背后的理由,连同示例,都会提供。然而,首先是一个关于如何抑制Numba可能引发的弃用警告的小节,以防止警告传播到正在使用Numba的代码中。
抑制弃用警告
所有 Numba 的弃用都是通过 NumbaDeprecationWarning
或 NumbaPendingDeprecationWarning
发出的,要抑制这些警告的报告,可以使用以下代码片段:
from numba.core.errors import NumbaDeprecationWarning, NumbaPendingDeprecationWarning
import warnings
warnings.simplefilter('ignore', category=NumbaDeprecationWarning)
warnings.simplefilter('ignore', category=NumbaPendingDeprecationWarning)
上面使用的 action
是 'ignore'
,还有其他可用的操作,更多信息请参见 警告过滤器 文档。
备注
强烈建议选择抑制这些警告的应用程序和库应将其 Numba 依赖项固定到合适的版本,因为其用户将不再意识到即将到来的不兼容性。
弃用 List 和 Set 类型的反射
反射 (reflection) 是 Numba 中用来描述确保编译代码对可变 Python 容器数据类型参数所做的更改在编译函数返回时对 Python 解释器可见的过程的术语。Numba 长期以来一直支持 list
和 set
数据类型的反射,而正是这种反射的支持计划被弃用,以便用更好的实现来替代。
弃用原因
首先回顾一下,为了让 Numba 能够在 nopython
模式下编译一个函数,所有变量必须通过类型推断确定具体的类型。在简单的情况下,很明显如何将 nopython
模式下对容器的更改反映回原始的 Python 容器。然而,对于嵌套容器类型的复杂数据结构(例如,整数的列表的列表),要高效且一致地反映这些更改很快就变得不可能。经过多年的经验,很明显提供这种行为既充满困难,又常常导致代码性能不佳(所有反映的数据必须在调用时通过特殊 API 将数据转换为本地格式,然后在返回时转换回 CPython 格式)。因此,由于问题追踪器中报告的问题数量庞大,以及 typed.Dict``(类型化字典)的新方法进展良好,核心开发者决定弃用所述的 ``reflection
行为。
影响的示例
目前仅发出即将更改的警告。未来代码如:
from numba import njit
@njit
def foo(x):
x.append(10)
a = [1, 2, 3]
foo(a)
将需要调整以使用 typed.List
实例,这个类型化容器与 类型化字典 功能相同。上述内容翻译的一个例子是:
from numba import njit
from numba.typed import List
@njit
def foo(x):
x.append(10)
a = [1, 2, 3]
typed_a = List()
[typed_a.append(x) for x in a]
foo(typed_a)
有关 typed.List
的更多信息,请参阅 类型化列表。此功能在 0.47.0 版本周期中进行了进一步的可用性增强。
日程安排
此功能将按照此计划被移除:
在版本0.44.0中将发出待弃用警告。
在完全移除之前,将至少在两个版本中给予显著的通知。
推荐
需要/依赖于已弃用行为的项目应将其对 Numba 的依赖固定在删除此行为之前的版本,或考虑遵循将发布的替换说明,说明如何调整以适应变化。
预期的替换
如上所述,typed.List
将被用于在 list
的情况下允许类似反射的功能,typed.Set
将为 set
提供等效功能(尚未实现!)。这种方法的优点是:
容器是有类型的意味着类型推断的工作量可以减少。
嵌套容器(容器的容器的…)更容易支持。
目前,在将数据转换为/从本地格式时产生的性能损失大部分被避免了。
Numba 的
typed.Dict
将能够使用这些容器作为值。
在使用 @jit
时,对象模式 的 回退 行为的弃用
备注
此功能已在 0.59.0 版本中移除,请参阅下面的计划部分。
numba.jit
装饰器长期以来一直遵循首先尝试在 nopython 模式 下编译被装饰函数的行为,如果此编译失败,它将 回退 并尝试再次编译,但这次是在 对象模式 下。正是这种 回退 行为将被弃用,其结果将是 numba.jit
将默认在 nopython 模式 下编译,而 对象模式 编译将变为仅 选择加入。
备注
在其他装饰器中使用 numba.jit
装饰器以提供一个简单的编译路径是相对常见的。由于这一变化,可能会从这些调用点引发弃用警告。为了避免这些警告,建议要么 抑制它们 如果应用程序不依赖于 对象模式 回退,要么检查装饰器的文档,看看如何将应用程序适当的选项传递给包装的 numba.jit
装饰器。Numba API 中的一个例子是 numba.vectorize
。这个装饰器只是将关键字参数转发到内部的 numba.jit
装饰器调用点,例如 @vectorize(nopython=True)
将是 @vectorize
在 nopython=True
模式下的适当声明。
弃用原因
fall-back 反复给用户带来了困惑,因为用户代码中看似无害的更改可能会导致性能的剧烈变化,例如,原本可能在 nopython 模式 下编译的代码可能会静默地切换到在 对象模式 下编译,例如:
from numba import jit
@jit
def foo():
l = []
for x in range(10):
l.append(x)
return l
foo()
assert foo.nopython_signatures # this was compiled in nopython mode
@jit
def bar():
l = []
for x in range(10):
l.append(x)
return reversed(l) # innocuous change, but no reversed support in nopython mode
bar()
assert not bar.nopython_signatures # this was not compiled in nopython mode
另一个移除 fall-back 的原因是,它对开发 Numba 的编译器工程师来说会造成混淆,因为它会导致内部状态问题,这些问题非常难以调试,并且使得操作编译器管道变得极其困难。
此外,长期以来,最佳实践一直被认为是将 numba.jit
装饰器中的 nopython 模式 关键字参数设置为 True
,并且任何用户努力都应该投入到使代码在这种模式下工作,因为如果代码不在此模式下工作,收益非常小。结果是,随着 Numba 的发展,对象模式 在实践中使用的数量及其一般效用已经减少。可以注意到,通过 循环提升 的概念可以获得一些小的改进,但在实践中使用这种情况的情况很少,通常是使用较旧版本的 Numba 的遗留问题,在这种情况下,这种行为得到了更好的适应/推荐使用带有 回退 的 @jit
。
影响的示例
目前,如果使用 @jit
装饰的代码使用了 回退 编译路径,则会发出即将更改的警告。未来的代码如:
@jit
def bar():
l = []
for x in range(10):
l.append(x)
return reversed(l)
bar()
将无法编译,会引发 TypingError
。
这一变化的另一个结果是,nopython
关键字参数将变得多余,因为 nopython 模式 将成为默认模式。因此,在此更改之后,提供 nopython=False
作为关键字参数将触发一个警告,指出隐式默认值已更改为 True
。本质上,在移除此功能后,此关键字将不再起作用。
日程安排
此功能已根据此时间表移除:
在版本 0.44.0 中发布了弃用警告。
在 0.57.0 版本中已给出显著通知。
该功能在 0.59.0 版本中已被移除。
推荐
需要/依赖于已弃用行为的项目应将其对 Numba 的依赖固定在移除此行为之前的版本。
关于适应计划中的弃用的一般建议:
当前使用 @jit
编译代码的用户可以提供 nopython=True
关键字参数,如果代码继续编译,则代码已经为这种变化做好了准备。如果代码无法编译,继续使用不带 nopython=True
的 @jit
装饰器,并分析函数的性能。然后移除装饰器,再次检查函数的性能。如果没有 @jit
装饰器存在的好处,考虑移除它!如果有 @jit
装饰器存在的好处,为了未来兼容性,提供关键字参数 forceobj=True
以确保函数始终在 对象模式 下编译。
关于“循环提升”功能用户的建议:
如果需要使用带有循环提升的对象模式编译,应通过向 @jit
装饰器提供关键字参数 forceobj=True
和 looplift=True
来明确声明。
对于设置 nopython=False
的用户的建议:
这基本上是在指定移除此功能之前的隐式默认值,要么移除关键字参数,要么将值更改为 True
。
弃用 generated_jit
顶级API函数 numba.generated_jit
提供了允许用户编写基于函数参数类型的不同实现的可JIT编译函数的功能。这是一个非常有用的概念,也是Numba内部实现的关键。
弃用原因
这一弃用有多个原因。
首先,generated_jit
打破了“JIT 透明性”的概念,因为如果 JIT 编译器被禁用,源代码的执行方式将与 JIT 编译器存在时不同。
其次,在内部,Numba 使用 numba.extending.overload
系列的装饰器来访问与 generated_jit
相当的功能。overload
系列的装饰器比 generated_jit
更强大,因为它们支持更多的选项,并且同时支持 CPU 和 CUDA 目标。实际上,generated_jit
的替代品已经存在,并且已经推荐和优选使用了一段时间。
第三,公共扩展API装饰器比 generated_jit
维护得更好。由于Numba资源有限,减少需要维护的功能重复部分将减轻这些资源的压力,这是一个重要的考虑因素。
有关 overload
装饰器家族的更多信息,请参阅 高级扩展API文档。
影响的示例
任何使用 generated_jit
的源代码在功能被移除后将无法工作。
日程安排
此功能已根据此时间表移除:
在版本 0.57.0 中发布了弃用警告。
移除发生在版本 0.59.0。
推荐
需要/依赖于已弃用行为的项目应将其对 Numba 的依赖固定在移除此行为之前的版本,或考虑遵循以下替换说明,这些说明概述了如何调整以适应变化。
替换
overload
装饰器提供了一个替代 generated_jit
功能的方案。以下是一个从一种方式转换到另一种方式的示例。首先使用 generated_jit
装饰器定义一个类型特化的函数调度:
from numba import njit, generated_jit, types
@generated_jit
def select(x):
if isinstance(x, types.Float):
def impl(x):
return x + 1
return impl
elif isinstance(x, types.UnicodeType):
def impl(x):
return x + " the number one"
return impl
else:
raise TypeError("Unsupported Type")
@njit
def foo(x):
return select(x)
print(foo(1.))
print(foo("a string"))
从概念上讲,generated_jit
类似于 overload
,但在 generated_jit
中,重载的函数是被装饰的函数。以上面的例子为基础,调整它以使用 overload
API:
from numba import njit, types
from numba.extending import overload
# A pure python implementation that will run if the JIT compiler is disabled.
def select(x):
if isinstance(x, float):
return x + 1
elif isinstance(x, str):
return x + " the number one"
else:
raise TypeError("Unsupported Type")
# An overload for the `select` function cf. generated_jit
@overload(select)
def ol_select(x):
if isinstance(x, types.Float):
def impl(x):
return x + 1
return impl
elif isinstance(x, types.UnicodeType):
def impl(x):
return x + " the number one"
return impl
else:
raise TypeError("Unsupported Type")
@njit
def foo(x):
return select(x)
print(foo(1.))
print(foo("a string"))
此外,使用 generated_jit
来分派一些更基本类型的用户可能会发现 Numba 对 isinstance
的支持已经足够,例如:
@njit # NOTE: standard @njit decorator.
def select(x):
if isinstance(x, float):
return x + 1
elif isinstance(x, str):
return x + " the number one"
else:
raise TypeError("Unsupported Type")
@njit
def foo(x):
return select(x)
print(foo(1.))
print(foo("a string"))
弃用 numba.pycc
模块
Numba 通过 numba.pycc
模块中的工具支持一定程度的提前编译(AOT)。这一功能对 Numba 项目非常重要,经过对当前方法可行性的评估,决定弃用它,转而开发新技术以更好地满足当前需求。
弃用原因
这一弃用有多个原因。
numba.pycc
工具创建的 C 扩展仅能从 Python 解释器中使用的符号,它们与使用 Numba 的 JIT 编译器编译的代码中的调用不兼容。这大大降低了预编译函数的实用性。numba.pycc
对setuptools``(以及 ``distutils
)有一定的依赖,这是 Numba 正在努力减少的部分,特别是由于即将在 Python 3.12 中移除distutils
。numba.pycc
编译链在功能集方面与 Numba 的 JIT 编译器相比非常有限,它在声明和链接内部及外部库方面也存在许多技术问题。numba.pycc
的用户数量被认为非常少,这一点在2022年10月4日的Numba公开会议讨论和问题 #8509 中有所体现。Numba 项目正在 AOT 编译器领域进行新的创新,维护者认为将资源用于开发这些新功能比维护和发展
numba.pycc
更为有效。
影响的示例
任何使用 numba.pycc
的源代码在功能被移除后将无法工作。
日程安排
此功能将按照此计划被移除:
在版本0.57.0中将发出待弃用警告。
一旦开发出替代方案,将发出弃用警告。
在完全移除之前,至少会在两个版本中给出弃用警告。
推荐
需要/依赖于已弃用行为的项目应将其对 Numba 的依赖固定在移除此行为之前的版本,或考虑遵循以下替换说明,这些说明概述了如何调整以适应变化。
替换
此功能的一个替代方案正在作为Numba 2023开发重点的一部分进行开发。在替代功能能够提供类似效用并提供升级路径之前,numba.pycc
模块不会被移除。在新技术被认为合适时,将发布替代说明。
弃用和移除 CUDA 工具包 < 11.2 及 CC < 5.0 的设备
已移除对低于11.2版本的CUDA工具包的支持。
对计算能力 < 5.0 的设备的支持已被弃用,并将在未来移除。
推荐
对于计算能力为3.0和3.2的设备,需要使用Numba 0.55.1或更早的版本。
应安装 CUDA 工具包 11.2 或更高版本。
日程安排
在 Numba 0.55.1 中:对 CC < 5.0 和 CUDA 工具包 < 10.2 的支持已被弃用。
在 Numba 0.56 中:移除了对 CC < 3.5 和 CUDA 工具包 < 10.2 的支持。
在 Numba 0.57 中:移除了对 CUDA 工具包 10.2 的支持。
在 Numba 0.58 中:移除了对 CUDA 工具包 11.0 和 11.1 的支持。
在未来的版本中:将不再支持 CC < 5.0。
弃用旧式 NUMBA_CAPTURED_ERRORS
在Numba中,使用 NUMBA_CAPTURED_ERRORS=old_style
环境变量已被弃用。
弃用原因
之前,这个变量允许控制Numba在编译过程中如何处理不继承自``numba.core.errors.NumbaError``的异常。默认的“旧样式”行为是捕获并包装这些错误,通常会掩盖原始异常。
新的“new_style”选项将非``NumbaError``异常视为硬错误,不捕获直接传播。这区分了编译错误与编译期间意外的异常。
旧样式最终将被移除,以支持新的行为。用户应迁移到设置 NUMBA_CAPTURED_ERRORS='new_style'
以选择加入新的异常处理。这将在未来成为默认设置。
影响
这一弃用的影响只会影响到那些正在扩展 Numba 功能的人。
推荐
扩展 Numba 的项目应设置
NUMBA_CAPTURED_ERRORS='new_style'
以进行测试,以查找编译期间引发非NumbaError
异常的所有位置。修改任何引发非
NumbaError
的代码,以指示编译错误,改为引发NumbaError
的子类。例如,不要引发TypeError
,而是引发numba.core.errors.NumbaTypeError
。
日程安排
在 Numba 0.58 中:
NUMBA_CAPTURED_ERRORS=old_style
已被弃用。当使用 old_style 错误捕获时,将会引发警告。在 Numba 0.59 中:显式设置
NUMBA_CAPTURED_ERRORS=old_style
将引发弃用警告。在 Numba 0.60 中:
NUMBA_CAPTURED_ERRORS=new_style
成为默认设置。在 Numba 0.61 中:将移除对
NUMBA_CAPTURED_ERRORS=old_style
的支持。