Skip to content

1.16。常见问题

原文: http://numba.pydata.org/numba-doc/latest/user/faq.html

1.16.1。编程

1.16.1.1。我可以将函数作为参数传递给 jitted 函数吗?

从 Numba 0.39 开始,你可以,只要函数参数也被 JIT 编译:

@jit(nopython=True)
def f(g, x):
    return g(x) + g(-x)

result = f(jitted_g_function, 1)

但是,使用作为函数的参数进行调度会产生额外的开销。如果这对您的应用程序很重要,您还可以使用工厂函数来捕获闭包中的函数参数:

def make_f(g):
    # Note: a new f() is created each time make_f() is called!
    @jit(nopython=True)
    def f(x):
        return g(x) + g(-x)
    return f

f = make_f(jitted_g_function)
result = f(1)

提高 Numba 功能的调度性能是一项持续的任务。

1.16.1.2。当我修改全局变量 时,Numba 似乎并不关心

Numba 将全局变量视为编译时常量。如果您希望在修改全局变量值时自己的 jitted 函数自行更新,一种解决方案是使用 recompile() 方法重新编译它。但这是一个相对较慢的操作,因此您可以决定重新构建代码并将全局变量转换为函数参数。

1.16.1.3。我可以调试 jitted 功能吗?

Numba 编译的代码目前不支持调用 pdb 或其他此类高级设施。但是,您可以通过设置 NUMBA_DISABLE_JIT 环境变量来暂时禁用编译。

1.16.1.4。如何创建 Fortran 排序的数组?

Numba 目前不支持大多数 Numpy 函数的order参数,例如 numpy.empty() (由于类型推断算法的限制)。您可以通过创建 C 有序数组然后转置它来解决此问题。例如:

a = np.empty((3, 5), order='F')
b = np.zeros(some_shape, order='F')

可以改写为:

a = np.empty((5, 3)).T
b = np.zeros(some_shape[::-1]).T

1.16.1.5。如何增加整数宽度?

默认情况下,Numba 通常使用整数变量的机器整数宽度。在 32 位机器上,您有时可能需要 64 位整数的大小。您可以简单地将相关变量初始化为np.int64(例如np.int64(0)而不是0)。它将传播到涉及这些变量的所有计算。

1.16.1.6。如何判断parallel=True是否有效?

环境变量 NUMBA_WARNINGS设置为非零,如果parallel=True转换因装饰的功能失败,将显示警告。

此外,设置环境变量 NUMBA_DEBUG_ARRAY_OPT_STATS将显示有关哪些运算符/调用转换为并行 for 循环的一些统计信息。

1.16.2。表现

1.16.2.1。 Numba 内联功能吗?

Numba 为 LLVM 提供了足够的信息,因此可以内联足够短的函数。这仅适用于 nopython 模式

1.16.2.2。 Numba 矢量化阵列计算(SIMD)吗?

Numba 本身并没有实现这样的优化,但它允许 LLVM 应用它们。

1.16.2.3。为什么我的循环没有矢量化?

Numba 默认启用 LLVM 中的循环向量化优化。虽然它是一个强大的优化,但并非所有循环都适用。有时,循环向量化可能会因内存访问模式等细微细节而失败。要从 LLVM 查看其他诊断信息,请添加以下行:

import llvmlite.binding as llvm
llvm.set_option('', '--debug-only=loop-vectorize')

这告诉 LLVM 从 loop-vectorize 传递到 stderr 打印调试信息。每个函数条目如下所示:

LV: Checking a loop in "<low-level symbol name>" from <function name>
LV: Loop hints: force=? width=0 unroll=0
...
LV: Vectorization is possible but not beneficial.
LV: Interleaving is not beneficial.

每个函数条目由空行分隔。拒绝矢量化的原因通常是在条目结束时。在上面的示例中,LLVM 拒绝了矢量化,因为这样做不会加速循环。在这种情况下,它可能是由于内存访问模式。例如,循环的数组可能不是连续的布局。

当内存访问模式不重要,无法确定访问内存区域时,LLVM 可能会拒绝以下消息:

LV: Can't vectorize due to memory conflicts

另一个常见原因是:

LV: Not vectorizing: loop did not meet vectorization requirements.

在这种情况下,矢量化被拒绝,因为矢量化代码可能表现不同。这是尝试打开fastmath=True以允许 fastmath 指令的情况。

1.16.2.4。 Numba 会自动并行化代码吗?

在某些情况下,它可以:

  • 具有target="parallel"选项的 Ufuncs 和 gufunc 将在多个线程上运行。
  • @jitparallel=True选项将尝试优化阵列操作并并行运行。它还增加了对prange()的支持,以显式并行化循环。

您也可以自己在多个线程上手动运行计算并使用nogil=True选项(参见释放 GIL )。 Numba 还可以使用其 CUDA 和 HSA 后端在 GPU 架构上实现并行执行。

1.16.2.5。 Numba 可以加快短期运行功能吗?

不显着。新用户有时希望 JIT 编译这样的函数:

def f(x, y):
    return x + y

并获得 Python 解释器的显着加速。但是 Numba 没有太多可以改进的地方:大部分时间都可能花在 CPython 的函数调用机制上,而不是函数本身。根据经验,如果函数执行时间不到 10μs:请保留它。

例外情况是你应该 JIT 编译该函数,如果它是从另一个 jitted 函数调用的。

1.16.2.6。当 JIT 编译一个复杂的函数时有一个延迟,我该如何改进呢?

尝试将cache=True传递给@jit装饰器。它会将编译后的版本保留在磁盘上供以后使用。

更激进的替代方案是提前编译

1.16.3。 GPU 编程

1.16.3.1。如何解决CUDA intialized before forking错误?

在 Linux 上,Python 标准库中的multiprocessing模块默认使用fork方法创建新进程。由于在父进程和子进程之间分配重复状态的进程,如果 CUDA 运行时在之前被初始化到 fork,CUDA 将无法在子进程中正常工作。 Numba 检测到这一点并使用CUDA initialized before forking消息引发CudaDriverError

避免此错误的一种方法是在子进程内或创建进程池后对numba.cuda函数进行所有调用。但是,这并不总是可行,因为您可能希望在启动进程池之前查询可用 GPU 的数量。在 Python 3 中,您可以更改进程启动方法,如多处理文档中所述。从fork切换到spawnforkserver将避免 CUDA 初始化问题,尽管子进程不会从其父进程继承任何全局变量。

1.16.4。与其他工具集成

1.16.4.1。我可以“冻结”使用 Numba 的应用程序吗?

如果您使用 PyInstaller 或类似的实用程序来冻结应用程序,则可能会遇到 llvmlite 的问题。 llvmlite 需要一个非 Python DLL 才能正常工作,但冻结实用程序不会自动检测到它。您必须通知冻结实用程序 DLL 的位置:它通常会被命名为llvmlite/binding/libllvmlite.sollvmlite/binding/llvmlite.dll,具体取决于您的系统。

1.16.4.2。在 Spyder 下运行两次脚本时出错

当您在 Spyder 下的控制台中运行脚本时,Spyder 会首先尝试重新加载现有模块。这对 Numba 不起作用,并且可能产生TypeError: No matching definition for argument type(s)之类的错误。

Spyder 首选项中有一个修复程序。打开“首选项”窗口,选择“控制台”,然后选择“高级设置”,单击“设置 UMR 排除模块”按钮,并在弹出的文本框内添加numba

要查看设置是否生效,请确保重新启动 IPython 控制台或内核。

1.16.4.3。为什么 Numba 抱怨当前的语言环境?

如果收到如下错误消息:

RuntimeError: Failed at nopython (nopython mode backend)
LLVM will produce incorrect floating-point code in the current locale

这意味着您遇到了 LLVM 错误,导致浮点常量处理不正确。已知某些第三方库(如 Qt 后端到 matplotlib)会发生这种情况。

要解决此问题,您需要将语言环境强制恢复为其默认值,例如:

import locale
locale.setlocale(locale.LC_NUMERIC, 'C')

1.16.5。杂项

1.16.5.1。如何在其他工作中引用/引用/确认 Numba?

对于学术用途,最好的选择是引用我们的 ACM 程序: Numba:基于 LLVM 的 Python JIT 编译器。



回到顶部