提交 99d7db30 编写于 作者: W wizardforcel

init

上级
+ [1. 用户手册](docs/11.md)
+ [1.1。 Numba 的约 5 分钟指南](docs/12.md)
+ [1.2。概述](docs/13.md)
+ [1.3。安装](docs/14.md)
+ [1.4。使用`@jit` 编译 Python 代码](docs/15.md)
+ [1.5。使用`@generated_jit` 进行灵活的专业化](docs/16.md)
+ [1.6。创建 Numpy 通用函数](docs/17.md)
+ [1.7。用@jitclass 编译 python 类](docs/18.md)
+ [1.8。使用`@cfunc` 创建 C 回调](docs/19.md)
+ [1.9。提前编译代码](docs/20.md)
+ [1.10。使用`@jit` 自动并行化](docs/21.md)
+ [1.11。使用`@stencil`装饰器](docs/22.md)
+ [1.12。从 JIT 代码 中回调到 Python 解释器](docs/23.md)
+ [1.13。性能提示](docs/24.md)
+ [1.14。线程层](docs/25.md)
+ [1.15。故障排除和提示](docs/26.md)
+ [1.16。常见问题](docs/27.md)
+ [1.17。示例](docs/28.md)
+ [1.18。会谈和教程](docs/29.md)
+ [2. 参考手册](docs/30.md)
+ [2.1。类型和签名](docs/31.md)
+ [2.2。即时编译](docs/32.md)
+ [2.3。提前编译](docs/33.md)
+ [2.4。公用事业](docs/34.md)
+ [2.5。环境变量](docs/35.md)
+ [2.6。支持的 Python 功能](docs/36.md)
+ [2.7。支持的 NumPy 功能](docs/37.md)
+ [2.8。与 Python 语义的偏差](docs/38.md)
+ [2.9。浮点陷阱](docs/39.md)
+ [2.10。 Python 2.7 寿命终止计划](docs/40.md)
+ [3. 用于 CUDA GPU 的 Numba](docs/41.md)
+ [3.1。概述](docs/42.md)
+ [3.2。编写 CUDA 内核](docs/43.md)
+ [3.3。内存管理](docs/44.md)
+ [3.4。编写设备功能](docs/45.md)
+ [3.5。 CUDA Python 中支持的 Python 功能](docs/46.md)
+ [3.6。支持的原子操作](docs/47.md)
+ [3.7。随机数生成](docs/48.md)
+ [3.8。设备管理](docs/49.md)
+ [3.10。示例](docs/50.md)
+ [3.11。使用 CUDA 模拟器 调试 CUDA Python](docs/51.md)
+ [3.12。 GPU 减少](docs/52.md)
+ [3.13。 CUDA Ufuncs 和广义 Ufuncs](docs/53.md)
+ [3.14。共享 CUDA 内存](docs/54.md)
+ [3.15。 CUDA 阵列接口](docs/55.md)
+ [3.16。 CUDA 常见问题](docs/56.md)
+ [4. CUDA Python 参考](docs/57.md)
+ [4.1。 CUDA 主机 API](docs/58.md)
+ [4.2。 CUDA 内核 API](docs/59.md)
+ [4.3。内存管理](docs/60.md)
+ [5. 用于 AMD ROC GPU 的 Numba](docs/61.md)
+ [5.1。概述](docs/62.md)
+ [5.2。编写 HSA 内核](docs/63.md)
+ [5.3。内存管理](docs/64.md)
+ [5.4。编写设备功能](docs/65.md)
+ [5.5。支持的原子操作](docs/66.md)
+ [5.6。代理商](docs/67.md)
+ [5.7。 ROC Ufuncs 和广义 Ufuncs](docs/68.md)
+ [5.8。示例](docs/69.md)
+ [6. 扩展 Numba](docs/70.md)
+ [6.1。高级扩展 API](docs/71.md)
+ [6.2。低级扩展 API](docs/72.md)
+ [6.3。示例:间隔类型](docs/73.md)
+ [7. 开发者手册](docs/74.md)
+ [7.1。贡献给 Numba](docs/75.md)
+ [7.2。 Numba 建筑](docs/76.md)
+ [7.3。多态调度](docs/77.md)
+ [7.4。关于发电机的注意事项](docs/78.md)
+ [7.5。关于 Numba Runtime 的注意事项](docs/79.md)
+ [7.6。使用 Numba Rewrite Pass 获得乐趣和优化](docs/80.md)
+ [7.7。实时变量分析](docs/81.md)
+ [7.8。上市](docs/82.md)
+ [7.9。模板注释](docs/83.md)
+ [7.10。关于自定义管道的注意事项](docs/84.md)
+ [7.11。环境对象](docs/85.md)
+ [7.12。哈希 的注意事项](docs/86.md)
+ [7.13。 Numba 项目路线图](docs/87.md)
+ [8. Numba 增强建议](docs/88.md)
+ [9. 术语表](docs/89.md)
\ No newline at end of file
# 1. 用户手册
\ No newline at end of file
# 1.1。 Numba 的约 5 分钟指南
> 原文: [http://numba.pydata.org/numba-doc/latest/user/5minguide.html](http://numba.pydata.org/numba-doc/latest/user/5minguide.html)
Numba 是 Python 的即时编译器,它最适用于使用 NumPy 数组和函数以及循环的代码。使用 Numba 的最常用方法是通过其装饰器集合,可以应用于您的函数来指示 Numba 编译它们。当调用 Numba 修饰函数时,它被编译为机器代码“及时”执行,并且您的全部或部分代码随后可以以本机机器代码速度运行!
开箱即用的 Numba 使用以下方法:
* 操作系统:Windows(32 位和 64 位),OSX 和 Linux(32 位和 64 位)
* 架构:x86,x86_64,ppc64le。在 armv7l,armv8l(aarch64)上进行实验。
* GPU:Nvidia CUDA。 AMD ROC 的实验。
* CPython 的
* NumPy 1.10 - 最新
## 1.1.1。我怎么得到它?
Numba 可用作 [Anaconda Python 发行版](https://www.anaconda.com/)[conda](https://conda.io/docs/) 软件包:
```py
$ conda install numba
```
Numba 还有轮子可供选择:
```py
$ pip install numba
```
Numba 也可以从源编译[,虽然我们不建议首次使用 Numba 用户。](installing.html#numba-source-install-instructions)
Numba 通常用作核心包,因此其依赖性保持在绝对最小值,但是,可以按如下方式安装额外的包以提供其他功能:
* `scipy` - 支持编译`numpy.linalg`功能。
* `colorama` - 支持回溯/错误消息中的颜色突出显示。
* `pyyaml` - 通过 YAML 配置文件启用 Numba 配置。
* `icc_rt` - 允许使用 Intel SVML(高性能短矢量数学库,仅限 x86_64)。安装说明在[性能提示](performance-tips.html#intel-svml)中。
## 1.1.2。 Numba 会为我的代码工作吗?
这取决于你的代码是什么样的,如果你的代码是以数字为导向的(做很多数学运算),使用 NumPy 和/或有很多循环,那么 Numba 通常是一个不错的选择。在这些例子中,我们将应用最基本的 Numba 的 JIT 装饰器`@jit`来尝试加速某些功能,以证明哪些功能正常,哪些功能不正常。
Numba 在代码看起来像这样:
```py
from numba import jit
import numpy as np
x = np.arange(100).reshape(10, 10)
@jit(nopython=True) # Set "nopython" mode for best performance, equivalent to @njit
def go_fast(a): # Function is compiled to machine code when called the first time
trace = 0
for i in range(a.shape[0]): # Numba likes loops
trace += np.tanh(a[i, i]) # Numba likes NumPy functions
return a + trace # Numba likes NumPy broadcasting
print(go_fast(x))
```
对于看起来像这样的代码,如果有的话,它将无法正常工作:
```py
from numba import jit
import pandas as pd
x = {'a': [1, 2, 3], 'b': [20, 30, 40]}
@jit
def use_pandas(a): # Function will not benefit from Numba jit
df = pd.DataFrame.from_dict(a) # Numba doesn't know about pd.DataFrame
df += 1 # Numba doesn't understand what this is
return df.cov() # or this!
print(use_pandas(x))
```
请注意,Numba 不理解 Pandas,因此 Numba 只是通过解释器运行此代码,但增加了 Numba 内部开销的成本!
## 1.1.3。什么是`nopython`模式?
Numba `@jit`装饰器基本上以两种编译模式运行,`nopython`模式和`object`模式。在上面的`go_fast`示例中,`@jit``@jit`装饰器中设置,这是指示 Numba 在`nopython`模式下运行。 `nopython`编译模式的行为本质上是编译装饰函数,以便它完全运行而不需要 Python 解释器的参与。这是使用 Numba `jit`装饰器的推荐和最佳实践方式,因为它可以获得最佳性能。
如果`nopython`模式下的编译失败,Numba 可以使用`object mode`进行编译,如果未设置`nopython=True`,这是`@jit`装饰器的后退模式(如上面的`use_pandas`示例所示)。在这种模式下,Numba 将识别它可以编译的循环,并将它们编译成在机器代码中运行的函数,并且它将运行解释器中的其余代码。为获得最佳性能,请避免使用此模式
## 1.1.4。如何衡量 Numba 的表现?
首先,回想一下 Numba 必须为执行函数的机器代码版本之前给出的参数类型编译函数,这需要时间。但是,一旦编译完成,Numba 会为所呈现的特定类型的参数缓存函数的机器代码版本。如果再次使用相同类型调用它,它可以重用缓存版本而不必再次编译。
测量性能时,一个非常常见的错误是不考虑上述行为,并使用一个简单的计时器对时间进行一次编码,该计时器包括在执行时编译函数所需的时间。
例如:
```py
from numba import jit
import numpy as np
import time
x = np.arange(100).reshape(10, 10)
@jit(nopython=True)
def go_fast(a): # Function is compiled and runs in machine code
trace = 0
for i in range(a.shape[0]):
trace += np.tanh(a[i, i])
return a + trace
# DO NOT REPORT THIS... COMPILATION TIME IS INCLUDED IN THE EXECUTION TIME!
start = time.time()
go_fast(x)
end = time.time()
print("Elapsed (with compilation) = %s" % (end - start))
# NOW THE FUNCTION IS COMPILED, RE-TIME IT EXECUTING FROM CACHE
start = time.time()
go_fast(x)
end = time.time()
print("Elapsed (after compilation) = %s" % (end - start))
```
这,例如打印:
```py
Elapsed (with compilation) = 0.33030009269714355
Elapsed (after compilation) = 6.67572021484375e-06
```
衡量 Numba JIT 对您的代码的影响的一个好方法是使用 [timeit](https://docs.python.org/3/library/timeit.html) 模块函数来执行时间,这些函数测量多次执行迭代,因此可以适应编译时间在第一次执行。
另外,如果编译时间成问题,Numba JIT 支持已编译函数的[磁盘缓存](../reference/jit-compilation.html#jit-decorator-cache),并且还具有 [Ahead-Of-Time](../reference/aot-compilation.html#aot-compilation) 编译模式。
## 1.1.5。它有多快?
假设 Numba 可以在`nopython`模式下运行,或者至少编译一些循环,它将针对您的特定 CPU 进行编译。加速因应用而异,但可以是一到两个数量级。 Numba 有一个[性能指南](performance-tips.html#performance-tips),涵盖了获得额外性能的常用选项。
## 1.1.6。 Numba 如何运作?
Numba 读取装饰函数的 Python 字节码,并将其与有关函数输入参数类型的信息相结合。它分析并优化您的代码,最后使用 LLVM 编译器库生成函数的机器代码版本,根据您的 CPU 功能量身定制。每次调用函数时都会使用此编译版本。
## 1.1.7。其他感兴趣的东西:
Numba 有很多装饰者,我们见过`@jit`,但也有:
* `@njit` - 这是`@jit(nopython=True)`的别名,因为它是如此常用!
* `@vectorize` - 产生 NumPy `ufunc`(支持所有`ufunc`方法)。 [文件在这里](vectorize.html#vectorize)
* `@guvectorize` - 产生 NumPy 广义`ufunc`[文件在这里](vectorize.html#guvectorize)
* `@stencil` - 将函数声明为类似模板操作的内核。 [文件在这里](stencil.html#numba-stencil)
* `@jitclass` - 用于 jit 感知类。 [文件在这里](jitclass.html#jitclass)
* `@cfunc` - 声明一个用作本机回调的函数(从 C / C ++等调用)。 [文件在这里](cfunc.html#cfunc)
* `@overload` - 注册您自己的函数实现,以便在 nopython 模式下使用,例如: `@overload(scipy.special.j0)`[文件在这里](../extending/high-level.html#high-level-extending)
一些装饰者提供额外选项:
* `parallel = True` - [使能](../reference/jit-compilation.html#jit-decorator-parallel)功能的[自动并行化](parallel.html#numba-parallel)
* `fastmath = True` - 为该功能启用 [fast-math](../reference/jit-compilation.html#jit-decorator-fastmath) 行为。
ctypes / cffi / cython 互操作性:
* `cffi` - `nopython`模式支持调用 [CFFI](../reference/pysupported.html#cffi-support) 功能。
* `ctypes` - `nopython`模式支持调用 [ctypes](../reference/pysupported.html#ctypes-support) 包装函数。 。
* Cython 导出函数[可调用](../extending/high-level.html#cython-support)
### 1.1.7.1。 GPU 目标:
Numba 可以靶向 [Nvidia CUDA](https://developer.nvidia.com/cuda-zone) 和(实验性) [AMD ROC](https://rocm.github.io/) GPU。您可以用纯 Python 编写内核,让 Numba 处理计算和数据移动(或明确地执行此操作)。点击 [CUDA](../cuda/index.html#cuda-index)[ROC](../roc/index.html#roc-index) 的 Numba 文档。
\ No newline at end of file
# 1.2。概述
> 原文: [http://numba.pydata.org/numba-doc/latest/user/overview.html](http://numba.pydata.org/numba-doc/latest/user/overview.html)
Numba 是 Python 数组和数值函数的编译器,它使您能够使用直接用 Python 编写的高性能函数来加速应用程序。
Numba 使用 [LLVM 编译器基础结构](http://llvm.org/)从纯 Python 代码生成优化的机器代码。通过一些简单的注释,面向数组和数学的 Python 代码可以及时优化到与 C,C ++和 Fortran 类似的性能,而无需切换语言或 Python 解释器。
Numba 的主要特点是:
* [即时代码生成](jit.html#jit)(在导入时或运行时,根据用户的喜好)
* CPU 的本机代码生成(默认)和 [GPU 硬件](../cuda/index.html)
* 与 Python 科学软件堆栈集成(感谢 Numpy)
以 Numba 优化函数为例,将 Numpy 数组作为参数,如下所示:
```py
@numba.jit
def sum2d(arr):
M, N = arr.shape
result = 0.0
for i in range(M):
for j in range(N):
result += arr[i,j]
return result
```
\ No newline at end of file
# 1.3。安装
> 原文: [http://numba.pydata.org/numba-doc/latest/user/installing.html](http://numba.pydata.org/numba-doc/latest/user/installing.html)
## 1.3.1。兼容性
Numba 与 Python 2.7 和 3.5 或更高版本以及 Numpy 版本 1.7 到 1.16 兼容(参见[本说明](../reference/numpysupported.html#numpy-support)的 1.16 支持限制)。
我们支持的平台是:
* Linux x86(32 位和 64 位)
* Linux ppcle64(POWER8)
* Windows 7 及更高版本(32 位和 64 位)
* OS X 10.9 及更高版本(64 位)
* 计算能力为 2.0 及更高版本的 NVIDIA GPU
* AMD ROC dGPU(仅限 Linux,不适用于 AMD Carrizo 或 Kaveri APU)
* ARMv7(32 位小端,如 Raspberry Pi 2 和 3)
[使用@jit](parallel.html#numba-parallel) 的自动并行化仅在 64 位平台上可用,并且在 Windows 上的 Python 2.7 中不受支持。
## 1.3.2。在 x86 / x86_64 / POWER 平台上使用 conda 进行安装
安装 Numba 并获得更新的最简单方法是使用`conda`,一个由 Anaconda,Inc。维护的跨平台软件包管理器和软件分发。您可以使用 [Anaconda](https://www.anaconda.com/download) 在一次下载中获得完整的堆栈,或 [Miniconda](https://conda.io/miniconda.html) ,它将安装 conda 环境所需的最小包。
安装 conda 后,只需输入:
```py
$ conda install numba
```
要么:
```py
$ conda update numba
```
请注意,与 Anaconda 一样,Numba 仅支持 64 位小端模式下的 PPC。
要为 Numba 启用 CUDA GPU 支持,请为您的平台安装 NVIDIA 的最新[图形驱动程序。 (请注意,默认情况下随许多 Linux 发行版提供的开源 Nouveau 驱动程序不支持 CUDA。)然后安装`cudatoolkit`包:](https://www.nvidia.com/Download/index.aspx)
```py
$ conda install cudatoolkit
```
您无需从 NVIDIA 安装 CUDA SDK。
## 1.3.3。在 x86 / x86_64 平台上使用 pip 进行安装
适用于 Windows,Mac 和 Linux 的二进制轮也可从 [PyPI](https://pypi.org/project/numba/) 获得。您可以使用`pip`安装 Numba:
```py
$ pip install numba
```
这将下载所有必需的依赖项。您不需要安装 LLVM 来使用 Numba(事实上,Numba 将忽略系统上安装的所有 LLVM 版本),因为所需的组件捆绑在 llvmlite 轮中。
要通过 <cite>pip</cite> 安装 Numba 使用 CUDA,您需要从 NVIDIA 安装 [CUDA SDK](https://developer.nvidia.com/cuda-downloads) 。然后,您可能需要设置以下环境变量,以便 Numba 可以找到所需的库:
* `NUMBAPRO_CUDA_DRIVER` - CUDA 驱动程序共享库文件的路径
* `NUMBAPRO_NVVM` - CUDA libNVVM 共享库文件的路径
* `NUMBAPRO_LIBDEVICE` - 包含.bc 文件的 CUDA libNVVM libdevice _ 目录 _ 的路径
## 1.3.4。启用 AMD ROCm GPU 支持
[ROCm 平台](https://rocm.github.io/)允许在 Linux 上使用 AMD GPU 进行 GPU 计算。要在 Numba 中启用 ROCm 支持,需要 conda,因此请先安装 Numba 0.40 或更高版本的 Anaconda 或 Miniconda 安装。然后:
1. 按照 [ROCm 安装说明](https://rocm.github.io/install.html)进行操作。
2.`numba`频道安装`roctools` conda 包:
```py
$ conda install -c numba roctools
```
有关示例笔记本,请参阅 [roc-examples](https://github.com/numba/roc-examples) 存储库。
## 1.3.5。在 Linux ARMv7 平台上安装
[Berryconda](https://github.com/jjhelmus/berryconda) 是 Raspberry Pi 的基于 conda 的 Python 发行版。我们现在将软件包上传到 Anaconda Cloud 上的`numba`频道,用于 32 位小端,基于 ARMv7 的电路板,目前包括 Raspberry Pi 2 和 3,但不包括 Pi 1 或 Zero。这些可以使用来自`numba`频道的 conda 进行安装:
```py
$ conda install -c numba numba
```
Berryconda 和 Numba 可能会在其他基于 Linux 的 ARMv7 系统上运行,但尚未经过测试。
## 1.3.6。从源 安装
从源代码安装 Numba 非常简单(类似于其他 Python 软件包),但由于需要特殊的 LLVM 构建,安装 [llvmlite](https://github.com/numba/llvmlite) 可能非常具有挑战性。如果您是为了 Numba 开发而从源代码构建的,请参阅[构建环境](../developer/contributing.html#buildenv),了解有关如何使用 conda 创建 Numba 开发环境的详细信息。
如果由于其他原因从源代码构建 Numba,请首先按照 [llvmlite 安装指南](https://llvmlite.readthedocs.io/en/latest/admin-guide/install.html)进行操作。完成后,您可以从 [Github](https://github.com/numba/numba) 下载最新的 Numba 源代码:
```py
$ git clone git://github.com/numba/numba.git
```
最新版本的源档案也可以在 [PyPI](https://pypi.org/project/numba/) 上找到。除`llvmlite`外,您还需要:
* 与 Python 安装兼容的 C 编译器。如果您使用的是 Anaconda,则可以安装 Linux 编译器 conda 软件包`gcc_linux-64``gxx_linux-64`,或 macOS 软件包`clang_osx-64``clangxx_osx-64`
* [NumPy](http://www.numpy.org/)
然后,您可以从源代码树的顶层构建和安装 Numba:
```py
$ python setup.py install
```
## 1.3.7。检查安装
您应该能够从 Python 提示符导入 Numba:
```py
$ python
Python 2.7.15 |Anaconda custom (x86_64)| (default, May 1 2018, 18:37:05)
[GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import numba
>>> numba.__version__
'0.39.0+0.g4e49566.dirty'
```
您还可以尝试执行 <cite>numba -s</cite> 命令来报告有关系统功能的信息:
```py
$ numba -s
System info:
--------------------------------------------------------------------------------
__Time Stamp__
2018-08-28 15:46:24.631054
__Hardware Information__
Machine : x86_64
CPU Name : haswell
CPU Features :
aes avx avx2 bmi bmi2 cmov cx16 f16c fma fsgsbase lzcnt mmx movbe pclmul popcnt
rdrnd sse sse2 sse3 sse4.1 sse4.2 ssse3 xsave xsaveopt
__OS Information__
Platform : Darwin-17.6.0-x86_64-i386-64bit
Release : 17.6.0
System Name : Darwin
Version : Darwin Kernel Version 17.6.0: Tue May 8 15:22:16 PDT 2018; root:xnu-4570.61.1~1/RELEASE_X86_64
OS specific info : 10.13.5 x86_64
__Python Information__
Python Compiler : GCC 4.2.1 Compatible Clang 4.0.1 (tags/RELEASE_401/final)
Python Implementation : CPython
Python Version : 2.7.15
Python Locale : en_US UTF-8
__LLVM information__
LLVM version : 6.0.0
__CUDA Information__
Found 1 CUDA devices
id 0 GeForce GT 750M [SUPPORTED]
compute capability: 3.0
pci device id: 0
pci bus id: 1
```
(输出由于长度而截断)
\ No newline at end of file
# 1.4。使用`@jit` 编译 Python 代码
> 原文: [http://numba.pydata.org/numba-doc/latest/user/jit.html](http://numba.pydata.org/numba-doc/latest/user/jit.html)
Numba 为代码生成提供了几个实用程序,但它的核心功能是 [`numba.jit()`](../reference/jit-compilation.html#numba.jit "numba.jit") 装饰器。使用这个装饰器,您可以通过 Numba 的 JIT 编译器标记一个函数进行优化。各种调用模式会触发不同的编译选项和行为。
## 1.4.1。基本用法
### 1.4.1.1。懒惰编译
使用`@jit`装饰器的推荐方法是让 Numba 决定何时以及如何优化:
```py
from numba import jit
@jit
def f(x, y):
# A somewhat trivial example
return x + y
```
在此模式下,编译将推迟到第一个函数执行。 Numba 将在调用时推断参数类型,并根据此信息生成优化代码。 Numba 还可以根据输入类型编译单独的特化。例如,使用整数或复数调用上面的`f()`函数将生成不同的代码路径:
```py
>>> f(1, 2)
3
>>> f(1j, 2)
(2+1j)
```
### 1.4.1.2。急切的编译
您还可以告诉 Numba 您期望的功能签名。函数`f()`现在看起来像:
```py
from numba import jit, int32
@jit(int32(int32, int32))
def f(x, y):
# A somewhat trivial example
return x + y
```
`int32(int32, int32)`是函数的签名。在这种情况下,相应的特化将由`@jit`装饰器编译,并且不允许其他专门化。如果您希望对编译器选择的类型进行细粒度控制(例如,使用单精度浮点数),这将非常有用。
如果省略返回类型,例如通过写`(int32, int32)`而不是`int32(int32, int32)`,Numba 将尝试为您推断它。函数签名也可以是字符串,您可以将其中的几个作为列表传递;有关详细信息,请参阅 [`numba.jit()`](../reference/jit-compilation.html#numba.jit "numba.jit") 文档。
当然,编译的函数给出了预期的结果:
```py
>>> f(1,2)
3
```
如果我们将`int32`指定为返回类型,则高位位被丢弃:
```py
>>> f(2**31, 2**31 + 1)
1
```
## 1.4.2。调用和内联其他功能
Numba 编译的函数可以调用其他编译函数。函数调用甚至可以在本机代码中内联,具体取决于优化器启发式。例如:
```py
@jit
def square(x):
return x ** 2
@jit
def hypot(x, y):
return math.sqrt(square(x) + square(y))
```
`@jit`装饰器 _ 必须将 _ 添加到任何此类库函数中,否则 Numba 可能会生成更慢的代码。
## 1.4.3。签名规格
显式`@jit`签名可以使用多种类型。以下是一些常见的:
* `void`是没有返回任何内容的函数的返回类型(从 Python 调用时实际返回`None`
* `intp``uintp`是指针大小的整数(分别是有符号和无符号)
* `intc``uintc`相当于 C `int``unsigned int`整数类型
* `int8``uint8``int16``uint16``int32``uint32``int64``uint64`是相应位宽的有限宽度整数(有符号和无符号)
* `float32``float64`分别是单精度和双精度浮点数
* `complex64``complex128`分别是单精度和双精度复数
* 数组类型可以通过索引任何数字类型来指定,例如一维单精度数组的`float32[:]`或 8 位整数的二维数组的`int8[:,:]`
## 1.4.4。编译选项
可以将许多仅关键字参数传递给`@jit`装饰器。
### 1.4.4.1。 `nopython`
Numba 有两种编译模式: [nopython 模式](../glossary.html#term-nopython-mode)[对象模式](../glossary.html#term-object-mode)。前者产生更快的代码,但有一些限制可以迫使 Numba 回到后者。为防止 Numba 退回,而是引发错误,请传递`nopython=True`
```py
@jit(nopython=True)
def f(x, y):
return x + y
```
也可以看看
[故障排除和提示](troubleshoot.html#numba-troubleshooting)
### 1.4.4.2。 `nogil`
每当 Numba 将 Python 代码优化为仅适用于本机类型和变量(而不是 Python 对象)的本机代码时,就不再需要持有 Python 的[全局解释器锁](https://docs.python.org/3/glossary.html#term-global-interpreter-lock "(in Python v3.7)")(GIL)。如果您通过`nogil=True`,Numba 将在输入此类编译函数时释放 GIL。
```py
@jit(nogil=True)
def f(x, y):
return x + y
```
使用 GIL 发布的代码与执行 Python 或 Numba 代码的其他线程(相同的编译函数或其他代码)同时运行,允许您利用多核系统。如果在[对象模式](../glossary.html#term-object-mode)中编译该功能,则无法进行此操作。
使用`nogil=True`时,您必须警惕多线程编程的常见缺陷(一致性,同步,竞争条件等)。
### 1.4.4.3。 `cache`
为了避免每次调用 Python 程序时的编译时间,可以指示 Numba 将函数编译的结果写入基于文件的缓存中。这是通过传递`cache=True`来完成的:
```py
@jit(cache=True)
def f(x, y):
return x + y
```
### 1.4.4.4。 `parallel`
为已知具有并行语义的函数中的那些操作启用自动并行化(和相关优化)。有关支持的操作列表,请参阅[使用@jit](parallel.html#numba-parallel) 自动并行化。通过`parallel=True`启用此功能,必须与`nopython=True`一起使用:
```py
@jit(nopython=True, parallel=True)
def f(x, y):
return x + y
```
也可以看看
[使用@jit](parallel.html#numba-parallel) 自动并行化
\ No newline at end of file
# 1.5。使用`@generated_jit` 进行灵活的专业化
> 原文: [http://numba.pydata.org/numba-doc/latest/user/generated-jit.html](http://numba.pydata.org/numba-doc/latest/user/generated-jit.html)
虽然 [`jit()`](../reference/jit-compilation.html#numba.jit "numba.jit") 装饰器在许多情况下都很有用,但有时您希望根据其输入类型编写具有不同实现的函数。 [`generated_jit()`](../reference/jit-compilation.html#numba.generated_jit "numba.generated_jit") 装饰器允许用户在编译时控制特化的选择,同时保持 JIT 函数的运行时执行速度。
## 1.5.1。示例
假设您要编写一个函数,该函数根据某些约定返回给定值是否为“缺失”值。为了示例,我们采用以下定义:
* 对于浮点参数,缺失值是`NaN`
* 对于 Numpy datetime64 和 timedelta64 参数,缺失值为`NaT`
* 其他类型没有缺失值的概念。
使用 [`generated_jit()`](../reference/jit-compilation.html#numba.generated_jit "numba.generated_jit") 装饰器可以轻松实现编译时逻辑:
```py
import numpy as np
from numba import generated_jit, types
@generated_jit(nopython=True)
def is_missing(x):
"""
Return True if the value is missing, False otherwise.
"""
if isinstance(x, types.Float):
return lambda x: np.isnan(x)
elif isinstance(x, (types.NPDatetime, types.NPTimedelta)):
# The corresponding Not-a-Time value
missing = x('NaT')
return lambda x: x == missing
else:
return lambda x: False
```
这里有几点需要注意:
* 使用参数的 [Numba 类型](../reference/types.html#numba-types)调用修饰函数,而不是它们的值。
* 修饰函数实际上并不计算结果,它返回一个 callable,实现给定类型的函数的实际定义。
* 可以在编译时预先计算一些数据(上面的`missing`变量),以便在编译的实现中重用它们。
* 函数定义使用与装饰函数相同的参数名称,这是确保按名称传递参数按预期工作所必需的。
## 1.5.2。编译选项
[`generated_jit()`](../reference/jit-compilation.html#numba.generated_jit "numba.generated_jit") 装饰器支持与 [`jit()`](../reference/jit-compilation.html#numba.jit "numba.jit") 装饰器相同的仅关键字参数,例如`nopython``cache`选项。
\ No newline at end of file
# 1.6。创建 Numpy 通用函数
> 原文: [http://numba.pydata.org/numba-doc/latest/user/vectorize.html](http://numba.pydata.org/numba-doc/latest/user/vectorize.html)
## 1.6.1。 `@vectorize`装饰器
Numba 的 vectorize 允许 Python 函数将标量输入参数用作 NumPy [ufuncs](http://docs.scipy.org/doc/numpy/reference/ufuncs.html) 。创建传统的 NumPy ufunc 并不是最直接的过程,而是涉及编写一些 C 代码。 Numba 让这很容易。使用 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 装饰器,Numba 可以将纯 Python 函数编译为一个 ufunc,它在 NumPy 阵列上运行的速度与用 C 编写的传统 ufunc 一样快。
使用 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") ,可以将函数编写为通过输入标量而不是数组进行操作。 Numba 将生成周围循环(或 _ 内核 _),允许对实际输入进行有效迭代。
[`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 装饰器有两种操作模式:
* 渴望或装饰时间,编译:如果您将一个或多个类型签名传递给装饰器,您将构建 Numpy 通用函数(ufunc)。本小节的其余部分描述了使用装饰时编译构建 ufunc。
* 懒惰或调用时编译:当没有给出任何签名时,装饰器会给你一个 Numba 动态通用函数( [`DUFunc`](../reference/jit-compilation.html#numba.DUFunc "numba.DUFunc") ),它在使用以前不支持的输入类型调用时动态编译新内核。后面的小节“[动态通用函数](#dynamic-universal-functions)”更深入地描述了这种模式。
如上所述,如果您将签名列表传递给 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 装饰器,您的函数将被编译为 Numpy ufunc。在基本情况下,只会传递一个签名:
```py
from numba import vectorize, float64
@vectorize([float64(float64, float64)])
def f(x, y):
return x + y
```
如果您传递了多个签名,请注意必须在最不具体的签名之前传递大多数特定签名(例如,在双精度浮点数之前单精度浮点数),否则基于类型的分派将无法按预期工作:
```py
@vectorize([int32(int32, int32),
int64(int64, int64),
float32(float32, float32),
float64(float64, float64)])
def f(x, y):
return x + y
```
该函数将按预期在指定的数组类型上工作:
```py
>>> a = np.arange(6)
>>> f(a, a)
array([ 0, 2, 4, 6, 8, 10])
>>> a = np.linspace(0, 1, 6)
>>> f(a, a)
array([ 0\. , 0.4, 0.8, 1.2, 1.6, 2\. ])
```
但它将无法在其他类型上工作:
```py
>>> a = np.linspace(0, 1+1j, 6)
>>> f(a, a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ufunc 'ufunc' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
```
你可能会问自己,“为什么我要经历这个而不是使用 [@jit](jit.html#jit) 装饰器编译一个简单的迭代循环?”。答案是 NumPy ufuncs 会自动获得其他功能,如缩小,累积或广播。使用上面的例子:
```py
>>> a = np.arange(12).reshape(3, 4)
>>> a
array([[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]])
>>> f.reduce(a, axis=0)
array([12, 15, 18, 21])
>>> f.reduce(a, axis=1)
array([ 6, 22, 38])
>>> f.accumulate(a)
array([[ 0, 1, 2, 3],
[ 4, 6, 8, 10],
[12, 15, 18, 21]])
>>> f.accumulate(a, axis=1)
array([[ 0, 1, 3, 6],
[ 4, 9, 15, 22],
[ 8, 17, 27, 38]])
```
也可以看看
[ufuncs 的标准功能](http://docs.scipy.org/doc/numpy/reference/ufuncs.html#ufunc)(NumPy 文档)。
[`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 装饰器支持多个 ufunc 目标:
| 目标 | 描述 |
| --- | --- |
| 中央处理器 | 单线程 CPU |
| 平行 | 多核 CPU |
| CUDA | CUDA GPU 注意这会创建一个类似 _ufunc 的 _ 对象。有关详细信息,请参阅 CUDA ufunc 的[文档。](../cuda/ufunc.html) |
一般准则是为不同的数据大小和算法选择不同的目标。 “cpu”目标适用于小数据大小(约小于 1KB)和低计算强度算法。它具有最少的开销。 “并行”目标适用于中等数据大小(大约小于 1MB)。线程增加了一点延迟。 “cuda”目标适用于大数据量(大约 1MB)和高计算强度算法。向 GPU 传输内存和从 GPU 传输内存会增加大量开销。
## 1.6.2。 `@guvectorize`装饰器
虽然 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 允许你一次写一个元素的 ufunc,但 [`guvectorize()`](../reference/jit-compilation.html#numba.guvectorize "numba.guvectorize") 装饰器更进一步,并允许你编写可以工作的 ufuncs 在输入数组的任意数量的元素上,并获取和返回不同维度的数组。典型的例子是运行中值或卷积滤波器。
[`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 函数相反, [`guvectorize()`](../reference/jit-compilation.html#numba.guvectorize "numba.guvectorize") 函数不返回其结果值:它们将其作为数组参数,必须由函数填充。这是因为数组实际上是由 NumPy 的调度机制分配的,调用机制调用 Numba 生成的代码。
这是一个非常简单的例子:
```py
@guvectorize([(int64[:], int64, int64[:])], '(n),()->(n)')
def g(x, y, res):
for i in range(x.shape[0]):
res[i] = x[i] + y
```
底层的 Python 函数只是将一个给定的标量(`y`)添加到一维数组的所有元素中。宣言更有意思。那里有两件事:
* 输入和输出 _ 布局 _ 的声明,符号形式:`(n),()-&gt;(n)`告诉 NumPy 该函数采用 _n_ 元素一维数组,一个标量(用符号表示为空元组`()`)并返回 _n_ 元素一维数组;
* `@vectorize`中支持的具体 _ 签名 _ 列表;这里我们只支持`int64`数组。
注意
1D 数组类型也可以接收标量参数(形状为`()`的参数)。在上面的例子中,第二个参数也可以声明为`int64[:]`。在这种情况下,该值必须由`y[0]`读取。
我们现在可以通过一个简单的例子来检查已编译的 ufunc 的作用:
```py
>>> a = np.arange(5)
>>> a
array([0, 1, 2, 3, 4])
>>> g(a, 2)
array([2, 3, 4, 5, 6])
```
好处是 NumPy 将根据其形状自动调度更复杂的输入:
```py
>>> a = np.arange(6).reshape(2, 3)
>>> a
array([[0, 1, 2],
[3, 4, 5]])
>>> g(a, 10)
array([[10, 11, 12],
[13, 14, 15]])
>>> g(a, np.array([10, 20]))
array([[10, 11, 12],
[23, 24, 25]])
```
注意
[`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize")[`guvectorize()`](../reference/jit-compilation.html#numba.guvectorize "numba.guvectorize") 都支持传递`nopython=True` [,如同@jit 装饰器](jit.html#jit-nopython)。使用它来确保生成的代码不会回退到[对象模式](../glossary.html#term-object-mode)
## 1.6.3。动态通用功能
如上所述,如果您没有将任何签名传递给 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 装饰器,您的 Python 函数将用于构建动态通用函数,或 [`DUFunc`](../reference/jit-compilation.html#numba.DUFunc "numba.DUFunc") 。例如:
```py
from numba import vectorize
@vectorize
def f(x, y):
return x * y
```
结果`f()`[`DUFunc`](../reference/jit-compilation.html#numba.DUFunc "numba.DUFunc") 实例,以没有支持的输入类型开头。在调用`f()`时,只要传递以前不支持的输入类型,Numba 就会生成新的内核。鉴于上面的示例,以下一组解释器交互说明了动态编译的工作原理:
```py
>>> f
<numba._DUFunc 'f'>
>>> f.ufunc
<ufunc 'f'>
>>> f.ufunc.types
[]
```
上面的例子显示 [`DUFunc`](../reference/jit-compilation.html#numba.DUFunc "numba.DUFunc") 实例不是 ufunc。而不是子类 ufunc, [`DUFunc`](../reference/jit-compilation.html#numba.DUFunc "numba.DUFunc") 实例通过保持 [`ufunc`](../reference/jit-compilation.html#numba.DUFunc.ufunc "numba.DUFunc.ufunc") 成员,然后将 ufunc 属性读取和方法调用委托给此成员(也称为类型聚合)来工作。当我们查看 ufunc 支持的初始类型时,我们可以验证没有。
我们试着打电话给`f()`
```py
>>> f(3,4)
12
>>> f.types # shorthand for f.ufunc.types
['ll->l']
```
如果这是一个普通的 Numpy ufunc,我们会看到一个异常抱怨 ufunc 无法处理输入类型。当我们用整数参数调用`f()`时,我们不仅会收到答案,而且我们可以验证 Numba 是否创建了支持 C `long`整数的循环。
我们可以通过使用不同的输入调用`f()`来添加其他循环:
```py
>>> f(1.,2.)
2.0
>>> f.types
['ll->l', 'dd->d']
```
我们现在可以验证 Numba 是否为处理浮点输入添加了第二个循环`"dd-&gt;d"`
如果我们将输入类型混合到`f()`,我们可以验证 [Numpy ufunc 强制转换规则](http://docs.scipy.org/doc/numpy/reference/ufuncs.html#casting-rules)是否仍然有效:
```py
>>> f(1,2.)
2.0
>>> f.types
['ll->l', 'dd->d']
```
此示例演示了使用混合类型调用`f()`会导致 Numpy 选择浮点循环,并将整数参数转换为浮点值。因此,Numba 没有创建一个特殊的`"dl-&gt;d"`内核。
[`DUFunc`](../reference/jit-compilation.html#numba.DUFunc "numba.DUFunc") 行为导致我们得到类似于上面“ [@vectorize 装饰器](#the-vectorize-decorator)”小节中给出的警告的点,但是在装饰器中没有签名声明顺序,呼叫顺序很重要。如果我们首先传入浮点参数,那么任何带有整数参数的调用都将被转换为双精度浮点值。例如:
```py
>>> @vectorize
... def g(a, b): return a / b
...
>>> g(2.,3.)
0.66666666666666663
>>> g(2,3)
0.66666666666666663
>>> g.types
['dd->d']
```
如果您需要对各种类型签名的精确支持,您应该在 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 装饰器中指定它们,而不是依赖于动态编译。
\ No newline at end of file
# 1.7。用@jitclass 编译 python 类
> 原文: [http://numba.pydata.org/numba-doc/latest/user/jitclass.html](http://numba.pydata.org/numba-doc/latest/user/jitclass.html)
注意
这是 jitclass 支持的早期版本。并非所有编译功能都已公开或实现。
Numba 通过 [`numba.jitclass()`](#numba.jitclass "numba.jitclass") 装饰器支持类的代码生成。可以使用此装饰器标记类以进行优化,同时指定每个字段的类型。我们将生成的类对象称为 jitclass。 jitclass 的所有方法都被编译成 nopython 函数。 jitclass 实例的数据在堆上作为 C 兼容结构分配,以便任何已编译的函数可以绕过解释器直接访问底层数据。
## 1.7.1。基本用法
这是一个 jitclass 的例子:
```py
import numpy as np
from numba import jitclass # import the decorator
from numba import int32, float32 # import the types
spec = [
('value', int32), # a simple scalar field
('array', float32[:]), # an array field
]
@jitclass(spec)
class Bag(object):
def __init__(self, value):
self.value = value
self.array = np.zeros(value, dtype=np.float32)
@property
def size(self):
return self.array.size
def increment(self, val):
for i in range(self.size):
self.array[i] = val
return self.array
```
(参见源代码树中 &lt;cite&gt;examples / jitclass.py&lt;/cite&gt; 的完整示例)
在上面的例子中,`spec`被提供为 2 元组的列表。元组包含字段的名称和字段的 numba 类型。或者,用户可以使用字典(`OrderedDict`优选地用于稳定字段排序),其将字段名称映射到类型。
该类的定义至少需要一个`__init__`方法来初始化每个定义的字段。未初始化的字段包含垃圾数据。可以定义方法和属性(仅限 getter 和 setter)。它们将自动编译。
## 1.7.2。支持操作
jitclasses 的以下操作在解释器和 numba 编译函数中都有效:
* 调用 jitclass 类对象来构造一个新实例(例如`mybag = Bag(123)`);
* 对属性和属性的读/写访问(例如`mybag.value`);
* 调用方法(例如`mybag.increment(3)`);
在 numba 编译函数中使用 jitclasses 更有效。可以内联简短方法(由 LLVM inliner 决定)。属性访问只是从 C 结构中读取。使用来自 intpreter 的 jitclasses 具有从解释器调用任何 numba 编译函数的相同开销。参数和返回值必须在 python 对象和本机表示之间取消装箱或装箱。当 jitclass 实例传递给解释器时,由 jitclass 封装的值不会被装入 python 对象。在对字段值的属性访问期间,它们被装箱。
## 1.7.3。限制
* jitclass 类对象被视为 numba 编译函数内的函数(构造函数)。
* `isinstance()`仅适用于口译员。
* 尚未优化在解释器中操作 jitclass 实例。
* 仅在 CPU 上提供对 jitclasses 的支持。 (注意:计划在将来的版本中支持 GPU 设备。)
## 1.7.4。装饰者:`@jitclass`
```py
numba.jitclass(spec)
```
用于创建 jitclass 的装饰器。
**参数**
* ```py
spec:
```
指定此类中每个字段的类型。必须是字典或序列。使用字典,使用 collections.OrderedDict 进行稳定排序。对于序列,它必须包含 2 元组(fieldname,fieldtype)。
**返回**
一个可调用的,它接受一个将被编译的类对象。
\ No newline at end of file
# 1.8。使用`@cfunc` 创建 C 回调
> 原文: [http://numba.pydata.org/numba-doc/latest/user/cfunc.html](http://numba.pydata.org/numba-doc/latest/user/cfunc.html)
与某些本机库(例如,用 C 或 C ++编写)连接可能需要编写本机回调以向库提供业务逻辑。 [`numba.cfunc()`](../reference/jit-compilation.html#numba.cfunc "numba.cfunc") 装饰器使用您选择的签名创建可从外部 C 代码调用的编译函数。
## 1.8.1。基本用法
`@cfunc`装饰器与`@jit`具有相似的用法,但有一个重要区别:传递单个签名是强制性的。它确定 C 回调的可见签名:
```py
from numba import cfunc
@cfunc("float64(float64, float64)")
def add(x, y):
return x + y
```
C 函数对象将已编译的 C 回调的地址公开为 [`address`](../reference/jit-compilation.html#CFunc.address "CFunc.address") 属性,以便您可以将其传递给任何外部 C 或 C ++库。它还暴露了指向该回调的 [`ctypes`](https://docs.python.org/3/library/ctypes.html#module-ctypes "(in Python v3.7)") 回调对象;该对象也可以从 Python 调用,从而可以轻松检查已编译的代码:
```py
@cfunc("float64(float64, float64)")
def add(x, y):
return x + y
print(add.ctypes(4.0, 5.0)) # prints "9.0"
```
## 1.8.2。示例
在这个例子中,我们将使用`scipy.integrate.quad`函数。该函数接受常规 Python 回调或包含在 [`ctypes`](https://docs.python.org/3/library/ctypes.html#module-ctypes "(in Python v3.7)") 回调对象中的 C 回调。
让我们定义一个纯 Python 的 integrand 并将其编译为 C 回调:
```py
>>> import numpy as np
>>> from numba import cfunc
>>> def integrand(t):
return np.exp(-t) / t**2
...:
>>> nb_integrand = cfunc("float64(float64)")(integrand)
```
我们可以将`nb_integrand`对象的 [`ctypes`](https://docs.python.org/3/library/ctypes.html#module-ctypes "(in Python v3.7)") 回调传递给`scipy.integrate.quad`,并检查结果是否与纯 Python 函数相同:
```py
>>> import scipy.integrate as si
>>> def do_integrate(func):
"""
Integrate the given function from 1.0 to +inf.
"""
return si.quad(func, 1, np.inf)
...:
>>> do_integrate(integrand)
(0.14849550677592208, 3.8736750296130505e-10)
>>> do_integrate(nb_integrand.ctypes)
(0.14849550677592208, 3.8736750296130505e-10)
```
使用已编译的回调,集成函数在每次评估被积函数时都不会调用 Python 解释器。在我们的例子中,集成速度提高了 18 倍:
```py
>>> %timeit do_integrate(integrand)
1000 loops, best of 3: 242 µs per loop
>>> %timeit do_integrate(nb_integrand.ctypes)
100000 loops, best of 3: 13.5 µs per loop
```
## 1.8.3。处理指针和数组内存
C 回调的一个不太重要的用例涉及对调用者传递的某些数据数组进行操作。由于 C 没有类似于 Numpy 数组的高级抽象,C 回调的签名将传递低级指针和大小参数。然而,回调的 Python 代码将期望利用 Numpy 数组的强大功能和表现力。
在下面的示例中,C 回调预计将在 2-d 数组上运行,签名为`void(double *input, double *output, int m, int n)`。你可以这样实现这样的回调:
```py
from numba import cfunc, types, carray
c_sig = types.void(types.CPointer(types.double),
types.CPointer(types.double),
types.intc, types.intc)
@cfunc(c_sig)
def my_callback(in_, out, m, n):
in_array = carray(in_, (m, n))
out_array = carray(out, (m, n))
for i in range(m):
for j in range(n):
out_array[i, j] = 2 * in_array[i, j]
```
[`numba.carray()`](../reference/utils.html#numba.carray "numba.carray") 函数将数据指针和形状作为输入,并返回给定形状的数组视图。假设数据按 C 顺序排列。如果数据以 Fortran 顺序排列,则应使用 [`numba.farray()`](../reference/utils.html#numba.farray "numba.farray")
## 1.8.4。处理 C 结构
### 1.8.4.1。用 CFFI
对于具有大量状态的应用程序,在 C 结构中传递数据很有用。为了简化与 C 代码的互操作性,numba 可以使用`numba.cffi_support.map_type``cffi`类型转换为 numba `Record`类型:
```py
from numba import cffi_support
nbtype = cffi_support.map_type(cffi_type, use_record_dtype=True)
```
注意
**use_record_dtype = True** 是必需的,否则指向 C 结构的指针将作为 void 指针返回。
例如:
```py
from cffi import FFI
src = """
/* Define the C struct */
typedef struct my_struct {
int i1;
float f2;
double d3;
float af4[7]; // arrays are supported
} my_struct;
/* Define a callback function */
typedef double (*my_func)(my_struct*, size_t);
"""
ffi = FFI()
ffi.cdef(src)
# Get the function signature from *my_func*
sig = cffi_support.map_type(ffi.typeof('my_func'), use_record_dtype=True)
# Make the cfunc
from numba import cfunc, carray
@cfunc(sig)
def foo(ptr, n):
base = carray(ptr, n) # view pointer as an array of my_struct
tmp = 0
for i in range(n):
tmp += base[i].i1 * base[i].f2 / base[i].d3
tmp += base[i].af4.sum() # nested arrays are like normal numpy array
return tmp
```
### 1.8.4.2。用`numba.types.Record.make_c_struct`
可以手动创建`numba.types.Record`类型以遵循 C 结构的布局。为此,请使用`Record.make_c_struct`,例如:
```py
my_struct = types.Record.make_c_struct([
# Provides a sequence of 2-tuples i.e. (name:str, type:Type)
('i1', types.int32),
('f2', types.float32),
('d3', types.float64),
('af4', types.NestedArray(dtype=types.float32, shape=(7,))),
])
```
由于 ABI 限制,应使用`types.CPointer(my_struct)`作为参数类型将结构作为指针传递。在`cfunc`体内,可以使用`carray`访问`my_struct*`
### 1.8.4.3。完整示例
请参阅`examples/notebooks/Accessing C Struct Data.ipynb`中的完整示例。
## 1.8.5。签名规范
显式`@cfunc`签名可以使用任何 [Numba 类型](../reference/types.html#numba-types),但只有它们的一个子集对 C 回调有意义。您通常应将自己限制为标量类型(例如`int8``float64`),指向它们的指针(例如`types.CPointer(types.int8)`)或指向`Record`类型的指针。
## 1.8.6。编译选项
可以将许多仅关键字参数传递给`@cfunc`装饰器:`nopython``cache`。它们的含义类似于`@jit`装饰器中的含义。
\ No newline at end of file
# 1.9。提前编译代码
> 原文: [http://numba.pydata.org/numba-doc/latest/user/pycc.html](http://numba.pydata.org/numba-doc/latest/user/pycc.html)
虽然 Numba 的主要用例是[即时编译](../glossary.html#term-just-in-time-compilation),但它也为[提前编译](../glossary.html#term-ahead-of-time-compilation)(AOT)提供了便利。
## 1.9.1。概述
### 1.9.1.1。好处
1. AOT 编译生成一个编译的扩展模块,它不依赖于 Numba:您可以在没有安装 Numba 的机器上分发模块(但需要 Numpy)。
2. 运行时没有编译开销(但请参阅`@jit` [缓存](jit.html#jit-cache)选项),也没有导入 Numba 的任何开销。
也可以看看
编译的扩展模块在 [Python 打包用户指南](https://packaging.python.org/en/latest/extensions/)中讨论。
### 1.9.1.2。限制
1. AOT 编译只允许常规功能,而不是 [ufuncs](../glossary.html#term-ufunc)
2. 您必须明确指定功能签名。
3. 每个导出的函数只能有一个签名(但您可以使用不同的名称导出多个不同的签名)。
4. AOT 编译为您的 CPU 架构系列生成通用代码(例如“x86-64”),而 JIT 编译生成针对您的特定 CPU 模型优化的代码。
## 1.9.2。用法
### 1.9.2.1。独立示例
```py
from numba.pycc import CC
cc = CC('my_module')
# Uncomment the following line to print out the compilation steps
#cc.verbose = True
@cc.export('multf', 'f8(f8, f8)')
@cc.export('multi', 'i4(i4, i4)')
def mult(a, b):
return a * b
@cc.export('square', 'f8(f8)')
def square(a):
return a ** 2
if __name__ == "__main__":
cc.compile()
```
如果您运行此 Python 脚本,它将生成名为`my_module`的扩展模块。根据您的平台,实际文件名可能是`my_module.so``my_module.pyd``my_module.cpython-34m.so`等。
生成的模块有三个功能:`multf``multi``square``multi`以 32 位整数(`i4`)运行,而`multf``square`以双精度浮点运算(`f8`):
```py
>>> import my_module
>>> my_module.multi(3, 4)
12
>>> my_module.square(1.414)
1.9993959999999997
```
### 1.9.2.2。 Distutils 整合
您还可以使用 distutils 或 setuptools 在`setup.py`脚本中集成扩展模块的编译步骤:
```py
from distutils.core import setup
from source_module import cc
setup(...,
ext_modules=[cc.distutils_extension()])
```
上面的`source_module`是定义`cc`对象的模块。像这样编译的扩展会自动包含在 Python 项目的构建文件中,因此您可以将它们分发到二进制包(如 wheel 或 Conda 包)中。请注意,在使用 conda 的情况下,用于 AOT 的编译器需要是 Anaconda 发行版中可用的编译器。
### 1.9.2.3。签名语法
导出签名的语法与`@jit`装饰器中的语法相同。您可以在[类型](../reference/types.html#numba-types)参考中阅读更多相关信息。
以下是在 1d 数组上导出二阶中心差异的实现的示例:
```py
@cc.export('centdiff_1d', 'f8[:](f8[:], f8)')
def centdiff_1d(u, dx):
D = np.empty_like(u)
D[0] = 0
D[-1] = 0
for i in range(1, len(D) - 1):
D[i] = (u[i+1] - 2 * u[i] + u[i-1]) / dx**2
return D
```
您也可以省略返回类型,然后由 Numba 推断:
```py
@cc.export('centdiff_1d', '(f8[:], f8)')
def centdiff_1d(u, dx):
# Same code as above
...
```
\ No newline at end of file
# 1.10。使用`@jit` 自动并行化
> 原文: [http://numba.pydata.org/numba-doc/latest/user/parallel.html](http://numba.pydata.org/numba-doc/latest/user/parallel.html)
[`jit()`](../reference/jit-compilation.html#numba.jit "numba.jit") 设置[并行](jit.html#parallel-jit-option)选项可启用 Numba 转换过程,该过程尝试自动并行化并对函数(部分)执行其他优化。目前,此功能仅适用于 CPU。
用户定义的函数内的一些操作,例如,向数组添加标量值已知具有并行语义。用户程序可以包含许多这样的操作,并且虽然每个操作可以单独并行化,但是这种方法通常由于较差的高速缓存行为而具有低廉的性能。相反,通过自动并行化,Numba 尝试在用户程序中识别此类操作,并将相邻的操作融合在一起,以形成一个或多个并行自动运行的内核。该过程完全自动化而无需修改用户程序,这与 Numba 的 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize")[`guvectorize()`](../reference/jit-compilation.html#numba.guvectorize "numba.guvectorize") 机制形成对比,其中需要手动操作来创建并行内核。
## 1.10.1。支持的操作
在本节中,我们列出了所有具有并行语义且我们尝试并行化的数组操作。
1. [案例研究支持的所有 numba 数组操作:数组表达式](../developer/rewrites.html#case-study-array-expressions),包括 Numpy 数组之间,数组和标量之间的常用算术函数,以及 Numpy ufuncs。它们通常被称为&lt;cite&gt;元素&lt;/cite&gt;&lt;cite&gt;逐点&lt;/cite&gt;数组操作:
&gt; * 一元算子:`+` `-` `~`
&gt; * 二元算子:`+` `-` `*` `/` `/?` `%` `|` `&gt;&gt;` `^` `&lt;&lt;` `&` `**` `//`
&gt; * 比较运算符:`==` `!=` `&lt;` `&lt;=` `&gt;` `&gt;=`
&gt; * [](../reference/numpysupported.html#supported-ufuncs)[nopython 模式](../glossary.html#term-nopython-mode)支持的 Numpy ufuncs。
&gt; * 用户定义 [`DUFunc`](../reference/jit-compilation.html#numba.DUFunc "numba.DUFunc") 至 [`vectorize()`](../reference/jit-compilation.html#numba.vectorize "numba.vectorize") 。
2. Numpy 减少函数`sum``prod``min``max``argmin``argmax`。此外,数组数学函数`mean``var``std`
3. Numpy 数组创建函数`zeros``ones``arange``linspace`和几个随机函数(rand,randn,ranf,random_sample,sample,random,standard_normal,chisquare,weibull,power,geometric,exponential,poisson ,瑞利,正常,均匀,贝塔,二项式,f,伽玛,对数正态,拉普拉斯,兰丁,三角形​​)。
4. Numpy `dot`函数在矩阵和向量之间,或两个向量之间。在所有其他情况下,使用 Numba 的默认实现。
5. 当操作数具有匹配的尺寸和大小时,上述操作也支持多维数组。不支持具有混合维度或大小的阵列之间的 Numpy 广播的完整语义,也不支持所选维度上的减少。
6. 数组赋值,其中目标是使用切片或布尔数组的数组选择,并且指定的值是标量或其他选择,其中切片范围或位阵列被推断为兼容。
7. `functools``reduce`运算符支持指定 1D Numpy 数组的并行减少,但初始值参数是必需的。
## 1.10.2。显式并行循环
代码转换传递的另一个特性(当`parallel=True`时)支持显式并行循环。可以使用 Numba 的`prange`而不是`range`来指定循环可以并行化。除了支持的减少之外,用户需要确保循环没有交叉迭代依赖性。
如果变量由二元函数/运算符使用其在循环体中的先前值更新,则自动推断减少。对于`+=``*=`运算符,自动推断减少的初始值。对于其他函数/运算符,reduce 变量应在进入`prange`循环之前保持标识值。对于标量和任意维度的数组,支持以这种方式减少。
下面的示例演示了一个带有缩减的并行循环(`A`是一维 Numpy 数组):
```py
from numba import njit, prange
@njit(parallel=True)
def prange_test(A):
s = 0
# Without "parallel=True" in the jit-decorator
# the prange statement is equivalent to range
for i in prange(A.shape[0]):
s += A[i]
return s
```
以下示例演示了二维数组的产品缩减:
```py
from numba import njit, prange
import numpy as np
@njit(parallel=True)
def two_d_array_reduction_prod(n):
shp = (13, 17)
result1 = 2 * np.ones(shp, np.int_)
tmp = 2 * np.ones_like(result1)
for i in prange(n):
result1 *= tmp
return result1
```
## 1.10.3。示例
在本节中,我们举例说明此功能如何帮助并行化 Logistic 回归:
```py
@numba.jit(nopython=True, parallel=True)
def logistic_regression(Y, X, w, iterations):
for i in range(iterations):
w -= np.dot(((1.0 / (1.0 + np.exp(-Y * np.dot(X, w))) - 1.0) * Y), X)
return w
```
我们不会讨论算法的细节,而是关注该程序如何使用自动并行化:
1. 输入`Y`是大小为`N`的向量,`X``N x D`矩阵,`w`是大小为`D`的向量。
2. 函数体是一个迭代循环,它更新变量`w`。循环体由一系列向量和矩阵运算组成。
3. 内部`dot`操作产生一个大小为`N`的向量,然后是标量和大小为`N`的向量之间的一系列算术运算,或两个大小为`N`的向量。
4. 外部`dot`产生一个大小为`D`的向量,然后在变量`w`上进行就地数组减法。
5. 通过自动并行化,将生成大小为`N`的数组的所有操作融合在一起,成为单个并行内核。这包括内部`dot`操作和后面的所有逐点数组操作。
6. 外部`dot`操作产生不同维度的结果数组,并且不与上述内核融合。
这里,利用并行硬件唯一需要的是为 [`jit()`](../reference/jit-compilation.html#numba.jit "numba.jit") 设置[并行](jit.html#parallel-jit-option)选项,而不对`logistic_regression`功能本身进行修改。如果我们使用 [`guvectorize()`](../reference/jit-compilation.html#numba.guvectorize "numba.guvectorize") 给出等价并行实现,则需要进行普遍的更改,重写代码以提取可并行化的内核计算,这既繁琐又具有挑战性。
## 1.10.4。诊断
注意
目前,并非所有并行变换和功能都可以通过代码生成过程进行跟踪。偶尔可能会丢失有关某些循环或变换的诊断信息。
[`jit()`](../reference/jit-compilation.html#numba.jit "numba.jit")[并行](jit.html#parallel-jit-option)选项可以生成有关自动并行化修饰代码的变换的诊断信息。这个信息可以通过两种方式访问​​,第一种是通过设置环境变量 [`NUMBA_PARALLEL_DIAGNOSTICS`](../reference/envvars.html#envvar-NUMBA_PARALLEL_DIAGNOSTICS) ,第二种是通过调用 [`parallel_diagnostics()`](../reference/jit-compilation.html#Dispatcher.parallel_diagnostics "Dispatcher.parallel_diagnostics") ,两种方法都给出相同的信息并打印至`STDOUT`。诊断信息中的详细程度由 1 到 4 之间的整数参数控制,其中 1 表示最小,4 表示最多。例如:
```py
@njit(parallel=True)
def test(x):
n = x.shape[0]
a = np.sin(x)
b = np.cos(a * a)
acc = 0
for i in prange(n - 2):
for j in prange(n - 1):
acc += b[i] + b[j + 1]
return acc
test(np.arange(10))
test.parallel_diagnostics(level=4)
```
生产:
```py
================================================================================
======= Parallel Accelerator Optimizing: Function test, example.py (4) =======
================================================================================
Parallel loop listing for Function test, example.py (4)
--------------------------------------|loop #ID
@njit(parallel=True) |
def test(x): |
n = x.shape[0] |
a = np.sin(x)---------------------| #0
b = np.cos(a * a)-----------------| #1
acc = 0 |
for i in prange(n - 2):-----------| #3
for j in prange(n - 1):-------| #2
acc += b[i] + b[j + 1] |
return acc |
--------------------------------- Fusing loops ---------------------------------
Attempting fusion of parallel loops (combines loops with similar properties)...
Trying to fuse loops #0 and #1:
- fusion succeeded: parallel for-loop #1 is fused into for-loop #0.
Trying to fuse loops #0 and #3:
- fusion failed: loop dimension mismatched in axis 0\. slice(0, x_size0.1, 1)
!= slice(0, $40.4, 1)
----------------------------- Before Optimization ------------------------------
Parallel region 0:
+--0 (parallel)
+--1 (parallel)
Parallel region 1:
+--3 (parallel)
+--2 (parallel)
--------------------------------------------------------------------------------
------------------------------ After Optimization ------------------------------
Parallel region 0:
+--0 (parallel, fused with loop(s): 1)
Parallel region 1:
+--3 (parallel)
+--2 (serial)
Parallel region 0 (loop #0) had 1 loop(s) fused.
Parallel region 1 (loop #3) had 0 loop(s) fused and 1 loop(s) serialized as part
of the larger parallel loop (#3).
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
---------------------------Loop invariant code motion---------------------------
Instruction hoisting:
loop #0:
Failed to hoist the following:
dependency: $arg_out_var.10 = getitem(value=x, index=$parfor__index_5.99)
dependency: $0.6.11 = getattr(value=$0.5, attr=sin)
dependency: $expr_out_var.9 = call $0.6.11($arg_out_var.10, func=$0.6.11, args=[Var($arg_out_var.10, example.py (7))], kws=(), vararg=None)
dependency: $arg_out_var.17 = $expr_out_var.9 * $expr_out_var.9
dependency: $0.10.20 = getattr(value=$0.9, attr=cos)
dependency: $expr_out_var.16 = call $0.10.20($arg_out_var.17, func=$0.10.20, args=[Var($arg_out_var.17, example.py (8))], kws=(), vararg=None)
loop #3:
Has the following hoisted:
$const58.3 = const(int, 1)
$58.4 = _n_23 - $const58.3
--------------------------------------------------------------------------------
```
为了帮助用户不熟悉使用[并行](jit.html#parallel-jit-option)选项时进行的转换,并帮助理解后续章节,提供了以下定义:
* ```py
Loop fusion
```
[循环融合](https://en.wikipedia.org/wiki/Loop_fission_and_fusion)是一种技术,其中具有等效边界的循环可以在某些条件下组合以产生具有较大主体的循环(旨在改善数据局部性)。
* ```py
Loop serialization
```
当在另一个`prange`驱动的回路内存在任意数量的`prange`驱动回路时,会发生回路串行化。在这种情况下,所有`prange`循环的最外层并行执行,并且任何内部`prange`循环(嵌套或其他)被视为基于标准`range`的循环。实质上,嵌套并行性不会发生。
* ```py
Loop invariant code motion
```
[循环不变代码运动](https://en.wikipedia.org/wiki/Loop-invariant_code_motion)是一种优化技术,它分析循环以查找可以移动到循环体外的语句而不改变执行循环的结果,然后这些语句被“提升”出循环保存重复计算。
* ```py
Allocation hoisting
```
分配提升是循环不变代码运动的一种特殊情况,由于一些常见的 NumPy 分配方法的设计,这是可能的。这个技术的解释最好由一个例子驱动:
```py
@njit(parallel=True)
def test(n):
for i in prange(n):
temp = np.zeros((50, 50)) # &lt;--- Allocate a temporary array with np.zeros()
for j in range(50):
temp[j, j] = i
# ...do something with temp
```
在内部,这被转换为大致如下:
```py
@njit(parallel=True)
def test(n):
for i in prange(n):
temp = np.empty((50, 50)) # &lt;--- np.zeros() is rewritten as np.empty()
temp[:] = 0 # &lt;--- and then a zero initialisation
for j in range(50):
temp[j, j] = i
# ...do something with temp
```
然后吊装后:
```py
@njit(parallel=True)
def test(n):
temp = np.empty((50, 50)) # &lt;--- allocation is hoisted as a loop invariant as `np.empty` is considered pure
for i in prange(n):
temp[:] = 0 # &lt;--- this remains as assignment is a side effect
for j in range(50):
temp[j, j] = i
# ...do something with temp
```
可以看出`np.zeros`分配被分成一个分配和一个赋值,然后分配从`i`中的循环中提升,这产生了更高效的代码,因为分配只发生一次。
### 1.10.4.1。并行诊断报告部分
该报告分为以下几个部分:
1. ```py
Code annotation
```
这是第一部分,包含带有循环的源代码,循环具有标识和枚举的并行语义。源代码右侧的`loop #ID`列与已识别的并行循环对齐。从示例中,`#0`是`np.sin`,`#1`是`np.cos`,`#2`和`#3`是`prange()`:
```py
Parallel loop listing for Function test, example.py (4)
--------------------------------------|loop #ID
@njit(parallel=True) |
def test(x): |
n = x.shape[0] |
a = np.sin(x)---------------------| #0
b = np.cos(a * a)-----------------| #1
acc = 0 |
for i in prange(n - 2):-----------| #3
for j in prange(n - 1):-------| #2
acc += b[i] + b[j + 1] |
return acc |
```
值得注意的是,循环 ID 按它们被发现的顺序枚举,这不一定与源中存在的顺序相同。此外,还应注意,并行变换使用静态计数器进行循环 ID 索引。因此,由于使用相同的计数器进行对用户不可见的内部优化/变换,循环 ID 索引可能不会从 0 开始。
2. ```py
Fusing loops
```
本节介绍在融合发现的循环时所做的尝试,注意哪些成功哪些失败。在未融合的情况下,给出了一个原因(例如,依赖于其他数据)。从示例:
```py
--------------------------------- Fusing loops ---------------------------------
Attempting fusion of parallel loops (combines loops with similar properties)...
Trying to fuse loops #0 and #1:
- fusion succeeded: parallel for-loop #1 is fused into for-loop #0.
Trying to fuse loops #0 and #3:
- fusion failed: loop dimension mismatched in axis 0\. slice(0, x_size0.1, 1)
!= slice(0, $40.4, 1)
```
可以看出,环`#0`和`#1`的融合被尝试并且这成功(两者都基于`x`的相同尺寸)。在`#0`和`#1`成功融合后,尝试在`#0`(现在包括融合的`#1`环)和`#3`之间进行融合。这种融合失败是因为存在环尺寸不匹配,`#0`是尺寸`x.shape`而`#3`是尺寸`x.shape[0] - 2`。
3. ```py
Before Optimization
```
本节显示了在进行任何优化之前代码中并行区域的结构,但是具有与其最终并行区域相关联的循环(这是在优化输出之前/之后直接进行比较)。如果存在不能融合的循环,则可能存在多个并行区域,在这种情况下,每个区域内的代码将并行执行,但每个并行区域将顺序运行。从示例:
```py
Parallel region 0:
+--0 (parallel)
+--1 (parallel)
Parallel region 1:
+--3 (parallel)
+--2 (parallel)
```
正如&lt;cite&gt;融合循环&lt;/cite&gt;部分所提到的,代码中必然存在两个并行区域。第一个包含循环`#0`和`#1`,第二个包含`#3`和`#2`,所有循环都标记为`parallel`,因为尚未进行优化。
4. ```py
After Optimization
```
本节显示优化发生后代码中并行区域的结构。同样,平行区域用它们相应的循环枚举,但是记录融合或序列化的这个时间循环并给出摘要。从示例:
```py
Parallel region 0:
+--0 (parallel, fused with loop(s): 1)
Parallel region 1:
+--3 (parallel)
+--2 (serial)
Parallel region 0 (loop #0) had 1 loop(s) fused.
Parallel region 1 (loop #3) had 0 loop(s) fused and 1 loop(s) serialized as part
of the larger parallel loop (#3).
```
可以注意到,并行区域 0 包含循环`#0`,并且如&lt;cite&gt;定影循环&lt;/cite&gt;部分所示,循环`#1`融合到循环`#0`中。还可以注意到,并行区域 1 包含循环`#3`并且该循环`#2`(内部`prange()`)已被序列化以在循环体`#3`中执行。
5. ```py
Loop invariant code motion
```
此部分显示优化发生后的每个循环:
* 未能提升的指示和失败的原因(依赖/不纯)。
* 悬挂的指示。
* 任何可能发生的分配吊装。
从示例:
```py
Instruction hoisting:
loop #0:
Failed to hoist the following:
dependency: $arg_out_var.10 = getitem(value=x, index=$parfor__index_5.99)
dependency: $0.6.11 = getattr(value=$0.5, attr=sin)
dependency: $expr_out_var.9 = call $0.6.11($arg_out_var.10, func=$0.6.11, args=[Var($arg_out_var.10, example.py (7))], kws=(), vararg=None)
dependency: $arg_out_var.17 = $expr_out_var.9 * $expr_out_var.9
dependency: $0.10.20 = getattr(value=$0.9, attr=cos)
dependency: $expr_out_var.16 = call $0.10.20($arg_out_var.17, func=$0.10.20, args=[Var($arg_out_var.17, example.py (8))], kws=(), vararg=None)
loop #3:
Has the following hoisted:
$const58.3 = const(int, 1)
$58.4 = _n_23 - $const58.3
```
首先要注意的是,此信息适用于高级用户,因为它指的是正在转换的函数的 [Numba IR](../glossary.html#term-numba-ir) 。例如,示例源中的表达式`a * a`部分转换为 IR 中的表达式`$arg_out_var.17 = $expr_out_var.9 * $expr_out_var.9`,这显然无法从`loop #0`中提升,因为它不是循环不变的!而在`loop #3`中,表达式`$const58.3 = const(int, 1)`来自源`b[j + 1]`,数字`1`显然是一个常数,因此可以从循环中提升。
也可以看看
[并行](jit.html#parallel-jit-option)[并行常见问题解答](faq.html#parallel-faqs)
\ No newline at end of file
# 1.11。使用`@stencil`装饰器
> 原文: [http://numba.pydata.org/numba-doc/latest/user/stencil.html](http://numba.pydata.org/numba-doc/latest/user/stencil.html)
模板是一种常见的计算模式,其中数组元素根据称为模板内核的某种固定模式进行更新。 Numba 提供`@stencil`装饰器,以便用户可以轻松指定模板内核,然后 Numba 生成将该内核应用于某个输入数组所需的循环代码。因此,模板装饰器允许更清晰,更简洁的代码,并且与[一起,并行 jit 选项](jit.html#parallel-jit-option)通过模板执行的并行化实现更高的性能。
## 1.11.1。基本用法
`@stencil`装饰器的示例用法:
```py
from numba import stencil
@stencil
def kernel1(a):
return 0.25 * (a[0, 1] + a[1, 0] + a[0, -1] + a[-1, 0])
```
模板内核由看起来像标准 Python 函数定义的内容指定,但是在数组索引方面有不同的语义。模板生成与输入数组具有相同大小和形状的输出数组,尽管取决于内核定义可能具有不同的类型。从概念上讲,模板内核对输出数组中的每个元素运行一次。模板内核的返回值是写入该特定元素的输出数组的值。
参数`a`表示应用内核的输入数组。索引到此数组是针对正在处理的输出数组的当前元素进行的。例如,如果正在处理元素`(x, y)`,则模板内核中的`a[0, 0]`对应于输入数组中的`a[x + 0, y + 0]`。类似地,模板内核中的`a[-1, 1]`对应于输入数组中的`a[x - 1, y + 1]`
根据指定的内核,内核可能不适用于输出数组的边界,因为这可能导致输入数组被越界访问。模板装饰器处理这种情况的方式取决于选择 [func_or_mode](#stencil-mode) 。默认模式是模板修饰器将输出数组的边框元素设置为零。
要在输入数组上调用模板,请将模板调用为常规函数,并将输入数组作为参数传递。例如,使用上面定义的内核:
```py
>>> import numpy as np
>>> input_arr = np.arange(100).reshape((10, 10))
array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74, 75, 76, 77, 78, 79],
[80, 81, 82, 83, 84, 85, 86, 87, 88, 89],
[90, 91, 92, 93, 94, 95, 96, 97, 98, 99]])
>>> output_arr = kernel1(input_arr)
array([[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
[ 0., 11., 12., 13., 14., 15., 16., 17., 18., 0.],
[ 0., 21., 22., 23., 24., 25., 26., 27., 28., 0.],
[ 0., 31., 32., 33., 34., 35., 36., 37., 38., 0.],
[ 0., 41., 42., 43., 44., 45., 46., 47., 48., 0.],
[ 0., 51., 52., 53., 54., 55., 56., 57., 58., 0.],
[ 0., 61., 62., 63., 64., 65., 66., 67., 68., 0.],
[ 0., 71., 72., 73., 74., 75., 76., 77., 78., 0.],
[ 0., 81., 82., 83., 84., 85., 86., 87., 88., 0.],
[ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]])
>>> input_arr.dtype
dtype('int64')
>>> output_arr.dtype
dtype('float64')
```
请注意,模板装饰器已确定指定的模板内核的输出类型为`float64`,因此将输出数组创建为`float64`,而输入数组的类型为`int64`
## 1.11.2。模板参数
模板内核定义可以采用以下规定的任意数量的参数。第一个参数必须是数组。输出数组的大小和形状将与第一个参数的大小和形状相同。其他参数可以是标量或数组。对于数组参数,这些数组必须至少与每个维度中的第一个参数(数组)一样大。所有此类输入数组参数的数组索引都是相对的。
## 1.11.3。内核形状推理和边界处理
在上面的示例中,在大多数情况下,模板内核中的数组索引将专门使用`Integer`文字。在这种情况下,模板装饰器能够分析模板内核以确定其大小。在上面的例子中,模板装饰器确定内核是`3 x 3`的形状,因为索引`-1``1`用于第一和第二维度。请注意,模板装饰器也可以正确处理非对称和非方形模板内核。
根据模板内核的大小,模板装饰器能够计算输出数组中边框的大小。如果将内核应用于输入数组的某个元素会导致索引超出范围,那么该元素属于输出数组的边界。在上面的示例中,在每个维度中访问点`-1``+1`,因此输出数组在所有维度中具有大小为 1 的边界。
如果可能,并行模式能够从简单表达式推断内核索引作为常量。例如:
```py
@njit(parallel=True)
def stencil_test(A):
c = 2
B = stencil(
lambda a, c: 0.3 * (a[-c+1] + a[0] + a[c-1]))(A, c)
return B
```
## 1.11.4。模板装饰器选项
注意
模板装饰器可以在将来增强,以提供用于边界处理的附加机制。目前,只实施了一种行为,`"constant"`(详见下文`func_or_mode`)。
### 1.11.4.1。 `neighborhood`
有时用`Integer`文字专门编写模板内核可能不方便。例如,假设我们想计算一组时间序列数据的 30 天移动平均值。可以编写`(a[-29] + a[-28] + ... + a[-1] + a[0]) / 30`,但模板装饰器使用`neighborhood`选项提供更简洁的形式:
```py
@stencil(neighborhood = ((-29, 0),))
def kernel2(a):
cumul = 0
for i in range(-29, 1):
cumul += a[i]
return cumul / 30
```
邻域选项是元组的元组。外元组的长度等于输入数组的维数。内元组的长度始终为 2,因为外元组的每个元素对应于相应维度中使用的最小和最大索引偏移量。
如果用户指定了邻域但内核访问了指定邻域之外的元素,则**行为未定义。**
### 1.11.4.2。 `func_or_mode`
可选的`func_or_mode`参数控制如何处理输出数组的边框。目前,只有一个受支持的值,`"constant"`。在`constant`模式下,在内核访问输入数组有效范围之外的元素的情况下,不应用模板内核。在这种情况下,输出数组中的那些元素被赋值为常量值,由`cval`参数指定。
### 1.11.4.3。 `cval`
可选的 cval 参数默认为零,但可以设置为任何所需的值,如果`func_or_mode`参数设置为`constant`,则该值用于输出数组的边界。在所有其他模式中忽略 cval 参数。 cval 参数的类型必须与模板内核的返回类型匹配。如果用户希望输出数组是从特定类型构造的,那么他们应该确保模板内核返回该类型。
### 1.11.4.4。 `standard_indexing`
默认情况下,模板内核中的所有数组访问都作为相对索引处理,如上所述。然而,有时将辅助数组(例如权重数组)传递给模板内核并使该数组使用标准 Python 索引而不是相对索引可能是有利的。为此,有一个模板装饰器选项`standard_indexing`,其值是一个字符串的集合,其名称与模板函数的参数相匹配,这些参数将使用标准 Python 索引而不是相对索引来访问:
```py
@stencil(standard_indexing=("b",))
def kernel3(a, b):
return a[-1] * b[0] + a[0] + b[1]
```
## 1.11.5。 `StencilFunc`
模板装饰器返回`StencilFunc`类型的可调用对象。 `StencilFunc`对象包含许多属性,但用户可能感兴趣的唯一属性是`neighborhood`属性。如果将`neighborhood`选项传递给模板装饰器,则提供的邻域将存储在此属性中。否则,在首次执行或编译时,系统如上所述计算邻域,然后将计算的邻域存储到该属性中。然后,如果用户希望验证所计算的邻域是正确的,则用户可以检查该属性。
## 1.11.6。模板调用选项
在内部,模板装饰器将指定的模板内核转换为常规的 Python 函数。此函数将具有与模板内核定义中指定的参数相同的参数,但也将包含以下可选参数。
### 1.11.6.1。 `out`
可选的`out`参数被添加到 Numba 生成的每个模板函数中。如果指定,`out`参数告诉 Numba 用户正在提供他们自己的预分配数组以用于模板的输出。在这种情况下,模板函数不会分配自己的输出数组。用户应确保模板内核的返回类型可以安全地转换为 [Numpy ufunc 强制转换规则](http://docs.scipy.org/doc/numpy/reference/ufuncs.html#casting-rules)之后的用户指定输出数组的元素类型。
示例用法如下所示:
```py
>>> import numpy as np
>>> input_arr = np.arange(100).reshape((10, 10))
>>> output_arr = np.full(input_arr.shape, 0.0)
>>> kernel1(input_arr, out=output_arr)
```
\ No newline at end of file
# 1.12。从 JIT 代码 中回调到 Python 解释器
> 原文: [http://numba.pydata.org/numba-doc/latest/user/withobjmode.html](http://numba.pydata.org/numba-doc/latest/user/withobjmode.html)
当 nopython-mode 函数需要回调到 Python 解释器来调用无法由 Numba 编译的代码时,有一些罕见但真实的情况。此类案件包括:
* 记录长期运行 JIT 函数的进度;
* 使用 Numba 当前不支持的数据结构;
* 使用 Python 调试器在 JIT 代码中调试。
当 Numba 回调到 Python 解释器时,必须发生以下情况:
* 获得 GIL;
* 将本机表示中的值转换回 Python 对象;
* 回调 Python 解释器;
* 将返回值从 Python 代码转换为本机表示;
* 发布 GIL。
这些步骤可能很昂贵。用户**不应该**依赖于此处描述的性能关键路径上的功能。
## 1.12.1。 `objmode`上下文管理器
警告
此功能很容易被误用。在使用此功能之前,用户应首先考虑其他方法以实现其预期目标。
```py
numba.objmode(*args, **kwargs)
```
创建一个上下文管理器,用于在 jitted 函数内部输入 _ 对象模式 _ 以使用解释器功能。 with-context 的主体被提升到一个在 _object-mode_ 中编译的函数。此转换过程受到限制,无法处理所有可能的 Python 代码。但是,用户可以将复杂的逻辑包装在另一个 Python 函数中,然后由解释器执行。
将此用作仅接受关键字参数的函数。参数名称必须与 with-block 的输出变量相对应。它们各自的值是表示预期类型的​​字符串。退出 with-context 时,输出变量将根据注释强制转换为预期的 nopython 类型。此过程与将 Python 对象传递到 nopython 函数的参数相同。
例:
```py
import numpy as np
from numba import njit, objmode
def bar(x):
# This code is executed by the interpreter.
return np.asarray(list(reversed(x.tolist())))
@njit
def foo():
x = np.arange(5)
y = np.zeros_like(x)
with objmode(y='intp[:]'): # annotate return type
# this region is executed by object-mode.
y += bar(x)
return y
```
注意
已知限制:
* with-block 无法使用传入的列表对象。
* with-block 无法使用传入的函数对象。
* with-block 不能`yield``break``return``raise`,执行将立即离开 with-block。
* with-block 不能包含带有语句的&lt;cite&gt;&lt;/cite&gt;
* 随机数发生器状态不同步;即 nopython-mode 和 object-mode 使用不同的 RNG 状态。
注意
在非 python 模式之外使用时,context-manager 无效。
警告
此功能是实验性的。支持的功能可能会随着或不通知而改变。
\ No newline at end of file
# 1.13。性能提示
> 原文: [http://numba.pydata.org/numba-doc/latest/user/performance-tips.html](http://numba.pydata.org/numba-doc/latest/user/performance-tips.html)
这是 Numba 中功能的简短指南,可以帮助您从代码中获得最佳性能。使用了两个例子,两者都完全是人为的,纯粹出于教学原因而存在,以激发讨论。第一个是三角恒等式`cos(x)^2 + sin(x)^2`的计算,第二个是矢量的简单元素方形平方根,它是求和的减少。所有性能数字仅供参考,除非另有说明,否则选自在`np.arange(1.e7)`输入的英特尔`i7-4790` CPU(4 个硬件线程)上运行。
注意
实现高性能代码的一种合理有效的方法是使用实​​际数据分析运行的代码,并使用它来指导性能调优。这里提供的信息是为了展示功能,而不是作为规范指导!
## 1.13.1。没有 Python 模式与对象模式
一个常见的模式是用`@jit`来装饰函数,因为这是 Numba 提供的最灵活的装饰器。 `@jit`本质上包含两种编译模式,首先它将尝试在没有 Python 模式下编译装饰函数,如果失败,它将再次尝试使用对象模式编译函数。虽然在对象模式下使用循环可以提高性能,但是在无 python 模式下编译函数确实是获得良好性能的关键。为了使得只使用没有 python 模式,并且如果编译失败,则引发异常,可以使用装饰器`@njit``@jit(nopython=True)`(为方便起见,第一个是第二个的别名)。
## 1.13.2。循环
虽然 NumPy 在矢量运算的使用方面已经形成了一个强有力的习惯,但 Numba 对循环也非常满意。对于熟悉 C 或 Fortran 的用户,以这种方式编写 Python 在 Numba 中可以正常工作(毕竟,LLVM 在编译 C 谱系语言时有很多用处)。例如:
```py
@njit
def ident_np(x):
return np.cos(x) ** 2 + np.sin(x) ** 2
@njit
def ident_loops(x):
r = np.empty_like(x)
n = len(x)
for i in range(n):
r[i] = np.cos(x[i]) ** 2 + np.sin(x[i]) ** 2
return r
```
当用`@njit`修饰时,上面以几乎相同的速度运行,没有装饰器,矢量化功能的速度提高了几个数量级。
| 功能名称 | @njit | 执行时间处理时间 |
| --- | --- | --- |
| `ident_np` | 没有 | 0.581s |
| `ident_np` | 是 | 0.659s |
| `ident_loops` | 没有 | 25.2s |
| `ident_loops` | 是 | 0.670s |
## 1.13.3。 Fastmath
在某些类别的应用中,严格的 IEEE 754 合规性不那么重要。因此,可以放松一些数字严谨性,以获得额外的性能。在 Numba 中实现此行为的方法是使用`fastmath`关键字参数:
```py
@njit(fastmath=False)
def do_sum(A):
acc = 0.
# without fastmath, this loop must accumulate in strict order
for x in A:
acc += np.sqrt(x)
return acc
@njit(fastmath=True)
def do_sum_fast(A):
acc = 0.
# with fastmath, the reduction can be vectorized as floating point
# reassociation is permitted.
for x in A:
acc += np.sqrt(x)
return acc
```
| 功能名称 | 执行时间处理时间 |
| --- | --- |
| `do_sum` | 35.2 毫秒 |
| `do_sum_fast` | 17.8 毫秒 |
## 1.13.4。并行=真
如果代码包含可并行的操作([和支持](parallel.html#numba-parallel-supported)),Numba 可以编译一个版本,它将在多个本机线程上并行运行(没有 GIL!)。这种并行化是自动执行的,只需添加`parallel`关键字参数即可启用:
```py
@njit(parallel=True)
def ident_parallel(A):
return np.cos(x) ** 2 + np.sin(x) ** 2
```
执行时间如下:
| 功能名称 | 执行时间处理时间 |
| --- | --- |
| `ident_parallel` | 112 毫秒 |
存在`parallel=True`的此功能的执行速度约为 NumPy 等效值的 5 倍,是标准`@njit`的 6 倍。
Numba 并行执行也支持显式并行循环声明,类似于 OpenMP。为了表明应该并行执行循环,应该使用`numba.prange`函数,这个函数的行为类似于 Python `range`,如果没有设置`parallel=True`,它只是作为`range`的别名。用`prange`诱导的循环可用于令人尴尬的并行计算和减少。
重新考虑 reduce over sum 示例,假设无法按顺序累积总和是安全的,`n`中的循环可以通过使用`prange`来并行化。此外,在这种情况下可以毫无顾虑地添加`fastmath=True`关键字参数,因为已经通过使用`parallel=True`(因为每个线程计算部分和)已经进行了无序执行有效的假设。
```py
@njit(parallel=True)
def do_sum_parallel(A):
# each thread can accumulate its own partial sum, and then a cross
# thread reduction is performed to obtain the result to return
n = len(A)
acc = 0.
for i in prange(n):
acc += np.sqrt(A[i])
return acc
@njit(parallel=True, fastmath=True)
def do_sum_parallel_fast(A):
n = len(A)
acc = 0.
for i in prange(n):
acc += np.sqrt(A[i])
return acc
```
执行时间如下,`fastmath`再次提高性能。
| 功能名称 | 执行时间处理时间 |
| --- | --- |
| `do_sum_parallel` | 9.81 毫秒 |
| `do_sum_parallel_fast` | 5.37 毫秒 |
## 1.13.5。英特尔 SVML
英特尔提供了一个简短的矢量数学库(SVML),其中包含大量优化的超越函数,可用作编译器内在函数。如果环境中存在`icc_rt`包(或者 SVML 库只是可定位的!),那么 Numba 会自动配置 LLVM 后端以尽可能使用 SVML 内部函数。 SVML 提供每个内在函数的高精度和低精度版本,并且使用的版本通过使用`fastmath`关键字来确定。默认使用精度高于`1 ULP`的高精度,但如果`fastmath`设置为`True`,则使用内在函数的低精度版本(`4 ULP`内的答案)。
首先使用 conda 获取 SVML,例如:
```py
conda install -c numba icc_rt
```
从上面重新运行身份函数示例`ident_np`,使用`@njit`和/或不使用 SVML 的各种选项组合,得到以下性能结果(输入大小`np.arange(1.e8)`)。作为参考,仅使用 NumPy 在`5.84s`中执行的功能:
| `@njit` kwargs | SVML | 执行时间处理时间 |
| --- | --- | --- |
| `None` | 没有 | 5.95s |
| `None` | 是 | 2.26s |
| `fastmath=True` | 没有 | 5.97s |
| `fastmath=True` | 是 | 1.8 秒 |
| `parallel=True` | 没有 | 1.36s |
| `parallel=True` | 是 | 0.624s |
| `parallel=True, fastmath=True` | 没有 | 1.32s |
| `parallel=True, fastmath=True` | 是 | 0.576s |
很明显,SVML 显着提高了该功能的性能。在不存在 SVML 的情况下`fastmath`的影响是零,这是预期的,因为原始函数中没有任何东西可以从放宽数字严格性中受益。
## 1.13.6。线性代数
Numba 在没有 Python 模式的情况下支持大多数`numpy.linalg`。内部实现依赖于 LAPACK 和 BLAS 库来完成数值工作,并从 SciPy 获取必要函数的绑定。因此,要在 Numba 的`numpy.linalg`函数中实现良好的性能,必须使用针对优化良好的 LAPACK / BLAS 库构建的 SciPy。在 Anaconda 发行版的情况下,SciPy 是针对英特尔的 MKL 构建的,该版本经过高度优化,因此 Numba 利用了这一性能。
\ No newline at end of file
# 1.14。线程层
> 原文: [http://numba.pydata.org/numba-doc/latest/user/threading-layer.html](http://numba.pydata.org/numba-doc/latest/user/threading-layer.html)
本节是关于 Numba 线程层,这是在内部用于执行通过使用 CPU 的`parallel`目标而发生的并行执行的库,即:
*`@jit``@njit`中使用`parallel=True` kwarg。
*`@vectorize``@guvectorize`中使用`target='parallel'` kwarg。
注意
如果代码库不使用`threading``multiprocessing`模块(或任何其他类型的并行),Numba 附带的线程层的默认值将运行良好,无需进一步操作!
## 1.14.1。哪些线程层可用?
有三个可用的线程层,它们的名称如下:
* `tbb` - 由英特尔 TBB 支持的线程层。
* `omp` - 由 OpenMP 支持的线程层。
* `workqueue` - 一个简单的内置工作共享任务调度程序。
实际上,保证存在的唯一螺纹层是`workqueue``omp`层需要存在合适的 OpenMP 运行时库。 `tbb`层需要存在 Intel 的 TBB 库,这些库可以通过 conda 命令获得:
```py
$ conda install tbb
```
如果您使用`pip`安装 Numba,可以通过运行以下命令启用 TBB:
```py
$ pip install tbb
```
由于 manylinux1 的兼容性问题和其他可移植性问题,在 PyPI 上的 Numba 二进制轮中禁用了 OpenMP 线程层。
注意
Numba 搜索并加载线程层的默认方式是容忍缺少库,不兼容的运行时等。
## 1.14.2。设置穿线层
通过环境变量`NUMBA_THREADING_LAYER`或通过赋值给`numba.config.THREADING_LAYER`设置线程层。如果使用设置线程层的编程方法,则必须在逻辑上在发生并行目标的任何基于 Numba 的编译之前进行。选择线程层有两种方法,第一种是选择在各种形式的并行执行下安全的线程层,第二种是通过线程层名称进行显式选择(例如`tbb`)。
### 1.14.2.1。选择安全并行执行的线程层
并行执行从根本上以四种形式从核心 Python 库派生(前三个也适用于通过其他方式使用并行执行的代码!):
* 来自`threading`模块的`threads`
* 来自`multiprocessing`模块`spawn``spawn`进程(Windows 上的默认值,仅适用于 Unix 上的 Python 3.4+)
* `fork`来自`multiprocessing`模块的进程通过`fork`(在 Unix 上是默认的,也是 Unix 上 Python 2 的唯一选项)。
* `fork`来自`multiprocessing`模块的进程通过使用`forkserver`(仅在 Unix 上的 Python 3 中可用)。基本上产生了一个新的过程,然后根据要求从这个新过程中生成叉子。
任何与这些形式的并行性一起使用的库必须在给定范例下表现出安全行为。因此,线程层选择方法旨在提供一种方法,以简单,跨平台和环境容忍的方式选择对给定范例安全的线程层库。可以提供给[设置机制](#numba-threading-layer-setting-mech)的选项如下:
* `default`没有提供特定的安全保证,是默认设置。
* `safe`是分叉和线程安全的,这需要安装`tbb`软件包(Intel TBB 库)。
* `forksafe`提供了一个 fork 安全库。
* `threadsafe`提供了一个线程安全的库。
要发现所选的线程层,可以在并行执行后调用函数`numba.threading_layer()`。例如,在没有安装 TBB 的 Linux 机器上:
```py
from numba import config, njit, threading_layer
import numpy as np
# set the threading layer before any parallel target compilation
config.THREADING_LAYER = 'threadsafe'
@njit(parallel=True)
def foo(a, b):
return a + b
x = np.arange(10.)
y = x.copy()
# this will force the compilation of the function, select a threading layer
# and then execute in parallel
foo(x, y)
# demonstrate the threading layer chosen
print("Threading layer chosen: %s" % threading_layer())
```
产生:
```py
Threading layer chosen: omp
```
这是有道理的,因为在 Linux 上存在的 GNU OpenMP 是线程安全的。
### 1.14.2.2。选择命名的线程层
高级用户可能希望为其用例选择特定的线程层,这可以通过直接向[设置机制](#numba-threading-layer-setting-mech)提供线程层名称来完成。选项和要求如下:
| 线程层名称 | 平台 | 要求 |
| --- | --- | --- |
| `tbb` | 所有 | `tbb`包(`$ conda install tbb`) |
| `omp` | Linux 的视窗 OSX | GNU OpenMP 库(很可能已经存在)MS OpenMP 库(很可能已经存在)`intel-openmp`包(`$ conda install intel-openmp`) |
| `workqueue` | 所有 | 没有 |
如果线程层未正确加载,Numba 将检测到这一点,并提供有关如何解决问题的提示。还应注意,Numba 诊断命令`numba -s`有一个`__Threading Layer Information__`部分,用于报告当前环境中线程层的可用性。
## 1.14.3。额外说明
线程层与 CPython 内部和系统级库的交互相当复杂,还需要注意一些其他事项:
* 英特尔 TBB 库的安装极大地拓宽了线程层选择过程中可用的选项。
* 在 Linux 上,`omp`线程层不是 fork 安全的,因为 GNU OpenMP 运行时库(`libgomp`)不是 fork 安全的。如果在使用`omp`线程层的程序中发生 fork,则会出现一种检测机制,它将尝试并正常终止分叉子项并将错误消息打印到`STDERR`
* 在 OSX 上,需要`intel-openmp`包来启用基于 OpenMP 的线程层。
* 对于运行 Python 2.7 的 Windows 用户,`tbb`线程层不可用。
\ No newline at end of file
此差异已折叠。
# 1.16。常见问题
> 原文: [http://numba.pydata.org/numba-doc/latest/user/faq.html](http://numba.pydata.org/numba-doc/latest/user/faq.html)
## 1.16.1。编程
### 1.16.1.1。我可以将函数作为参数传递给 jitted 函数吗?
从 Numba 0.39 开始,你可以,只要函数参数也被 JIT 编译:
```py
@jit(nopython=True)
def f(g, x):
return g(x) + g(-x)
result = f(jitted_g_function, 1)
```
但是,使用作为函数的参数进行调度会产生额外的开销。如果这对您的应用程序很重要,您还可以使用工厂函数来捕获闭包中的函数参数:
```py
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()`](../reference/jit-compilation.html#Dispatcher.recompile "Dispatcher.recompile") 方法重新编译它。但这是一个相对较慢的操作,因此您可以决定重新构建代码并将全局变量转换为函数参数。
### 1.16.1.3。我可以调试 jitted 功能吗?
Numba 编译的代码目前不支持调用 [`pdb`](https://docs.python.org/3/library/pdb.html#module-pdb "(in Python v3.7)") 或其他此类高级设施。但是,您可以通过设置 [`NUMBA_DISABLE_JIT`](../reference/envvars.html#envvar-NUMBA_DISABLE_JIT) 环境变量来暂时禁用编译。
### 1.16.1.4。如何创建 Fortran 排序的数组?
Numba 目前不支持大多数 Numpy 函数的`order`参数,例如 [`numpy.empty()`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.empty.html#numpy.empty "(in NumPy v1.16)") (由于[类型推断](../glossary.html#term-type-inference)算法的限制)。您可以通过创建 C 有序数组然后转置它来解决此问题。例如:
```py
a = np.empty((3, 5), order='F')
b = np.zeros(some_shape, order='F')
```
可以改写为:
```py
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`是否有效?
[环境变量](../reference/envvars.html#numba-envvars) `NUMBA_WARNINGS`设置为非零,如果`parallel=True`转换因装饰的功能失败,将显示警告。
此外,设置[环境变量](../reference/envvars.html#numba-envvars) `NUMBA_DEBUG_ARRAY_OPT_STATS`将显示有关哪些运算符/调用转换为并行 for 循环的一些统计信息。
## 1.16.2。表现
### 1.16.2.1。 Numba 内联功能吗?
Numba 为 LLVM 提供了足够的信息,因此可以内联足够短的函数。这仅适用于 [nopython 模式](../glossary.html#term-nopython-mode)
### 1.16.2.2。 Numba 矢量化阵列计算(SIMD)吗?
Numba 本身并没有实现这样的优化,但它允许 LLVM 应用它们。
### 1.16.2.3。为什么我的循环没有矢量化?
Numba 默认启用 LLVM 中的循环向量化优化。虽然它是一个强大的优化,但并非所有循环都适用。有时,循环向量化可能会因内存访问模式等细微细节而失败。要从 LLVM 查看其他诊断信息,请添加以下行:
```py
import llvmlite.binding as llvm
llvm.set_option('', '--debug-only=loop-vectorize')
```
这告诉 LLVM 从 **loop-vectorize** 传递到 stderr 打印调试信息。每个函数条目如下所示:
```py
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 可能会拒绝以下消息:
```py
LV: Can't vectorize due to memory conflicts
```
另一个常见原因是:
```py
LV: Not vectorizing: loop did not meet vectorization requirements.
```
在这种情况下,矢量化被拒绝,因为矢量化代码可能表现不同。这是尝试打开`fastmath=True`以允许 fastmath 指令的情况。
### 1.16.2.4。 Numba 会自动并行化代码吗?
在某些情况下,它可以:
* 具有`target="parallel"`选项的 Ufuncs 和 gufunc 将在多个线程上运行。
* `@jit``parallel=True`选项将尝试优化阵列操作并并行运行。它还增加了对`prange()`的支持,以显式并行化循环。
您也可以自己在多个线程上手动运行计算并使用`nogil=True`选项(参见[释放 GIL](jit.html#jit-nogil) )。 Numba 还可以使用其 CUDA 和 HSA 后端在 GPU 架构上实现并行执行。
### 1.16.2.5。 Numba 可以加快短期运行功能吗?
不显着。新用户有时希望 JIT 编译这样的函数:
```py
def f(x, y):
return x + y
```
并获得 Python 解释器的显着加速。但是 Numba 没有太多可以改进的地方:大部分时间都可能花在 CPython 的函数调用机制上,而不是函数本身。根据经验,如果函数执行时间不到 10μs:请保留它。
例外情况是你应该 JIT 编译该函数,如果它是从另一个 jitted 函数调用的。
### 1.16.2.6。当 JIT 编译一个复杂的函数时有一个延迟,我该如何改进呢?
尝试将`cache=True`传递给`@jit`装饰器。它会将编译后的版本保留在磁盘上供以后使用。
更激进的替代方案是[提前编译](pycc.html#pycc)
## 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 中,您可以更改进程启动方法,如[多处理文档](https://docs.python.org/3.6/library/multiprocessing.html#contexts-and-start-methods)中所述。从`fork`切换到`spawn``forkserver`将避免 CUDA 初始化问题,尽管子进程不会从其父进程继承任何全局变量。
## 1.16.4。与其他工具集成
### 1.16.4.1。我可以“冻结”使用 Numba 的应用程序吗?
如果您使用 PyInstaller 或类似的实用程序来冻结应用程序,则可能会遇到 llvmlite 的问题。 llvmlite 需要一个非 Python DLL 才能正常工作,但冻结实用程序不会自动检测到它。您必须通知冻结实用程序 DLL 的位置:它通常会被命名为`llvmlite/binding/libllvmlite.so``llvmlite/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 抱怨当前的语言环境?
如果收到如下错误消息:
```py
RuntimeError: Failed at nopython (nopython mode backend)
LLVM will produce incorrect floating-point code in the current locale
```
这意味着您遇到了 LLVM 错误,导致浮点常量处理不正确。已知某些第三方库(如 Qt 后端到 matplotlib)会发生这种情况。
要解决此问题,您需要将语言环境强制恢复为其默认值,例如:
```py
import locale
locale.setlocale(locale.LC_NUMERIC, 'C')
```
## 1.16.5。杂项
### 1.16.5.1。如何在其他工作中引用/引用/确认 Numba?
对于学术用途,最好的选择是引用我们的 ACM 程序: [Numba:基于 LLVM 的 Python JIT 编译器。](http://dl.acm.org/citation.cfm?id=2833162&dl=ACM&coll=DL)
\ No newline at end of file
# 1.17。示例
> 原文: [http://numba.pydata.org/numba-doc/latest/user/examples.html](http://numba.pydata.org/numba-doc/latest/user/examples.html)
## 1.17.1。 Mandelbrot
```py
#! /usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function, division, absolute_import
from timeit import default_timer as timer
from matplotlib.pylab import imshow, jet, show, ion
import numpy as np
from numba import jit
@jit
def mandel(x, y, max_iters):
"""
Given the real and imaginary parts of a complex number,
determine if it is a candidate for membership in the Mandelbrot
set given a fixed number of iterations.
"""
i = 0
c = complex(x,y)
z = 0.0j
for i in range(max_iters):
z = z*z + c
if (z.real*z.real + z.imag*z.imag) >= 4:
return i
return 255
@jit
def create_fractal(min_x, max_x, min_y, max_y, image, iters):
height = image.shape[0]
width = image.shape[1]
pixel_size_x = (max_x - min_x) / width
pixel_size_y = (max_y - min_y) / height
for x in range(width):
real = min_x + x * pixel_size_x
for y in range(height):
imag = min_y + y * pixel_size_y
color = mandel(real, imag, iters)
image[y, x] = color
return image
image = np.zeros((500 * 2, 750 * 2), dtype=np.uint8)
s = timer()
create_fractal(-2.0, 1.0, -1.0, 1.0, image, 20)
e = timer()
print(e - s)
imshow(image)
#jet()
#ion()
show()
```
## 1.17.2。移动平均线
```py
#!/usr/bin/env python
"""
A moving average function using @guvectorize.
"""
import numpy as np
from numba import guvectorize
@guvectorize(['void(float64[:], intp[:], float64[:])'], '(n),()->(n)')
def move_mean(a, window_arr, out):
window_width = window_arr[0]
asum = 0.0
count = 0
for i in range(window_width):
asum += a[i]
count += 1
out[i] = asum / count
for i in range(window_width, len(a)):
asum += a[i] - a[i - window_width]
out[i] = asum / count
arr = np.arange(20, dtype=np.float64).reshape(2, 10)
print(arr)
print(move_mean(arr, 3))
```
## 1.17.3。多线程
下面的代码展示了使用 [nogil](jit.html#jit-nogil) 功能时潜在的性能提升。例如,在 4 核机器上,我打印出以下结果:
```py
numpy (1 thread) 145 ms
numba (1 thread) 128 ms
numba (4 threads) 35 ms
```
注意
在 Python 3 下,您可以使用标准的 [concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html) 模块,而不是手工生成线程和调度任务。
```py
#!/usr/bin/env python
from __future__ import print_function, division, absolute_import
import math
import threading
from timeit import repeat
import numpy as np
from numba import jit
nthreads = 4
size = 10**6
def func_np(a, b):
"""
Control function using Numpy.
"""
return np.exp(2.1 * a + 3.2 * b)
@jit('void(double[:], double[:], double[:])', nopython=True, nogil=True)
def inner_func_nb(result, a, b):
"""
Function under test.
"""
for i in range(len(result)):
result[i] = math.exp(2.1 * a[i] + 3.2 * b[i])
def timefunc(correct, s, func, *args, **kwargs):
"""
Benchmark *func* and print out its runtime.
"""
print(s.ljust(20), end=" ")
# Make sure the function is compiled before we start the benchmark
res = func(*args, **kwargs)
if correct is not None:
assert np.allclose(res, correct), (res, correct)
# time it
print('{:>5.0f} ms'.format(min(repeat(lambda: func(*args, **kwargs),
number=5, repeat=2)) * 1000))
return res
def make_singlethread(inner_func):
"""
Run the given function inside a single thread.
"""
def func(*args):
length = len(args[0])
result = np.empty(length, dtype=np.float64)
inner_func(result, *args)
return result
return func
def make_multithread(inner_func, numthreads):
"""
Run the given function inside *numthreads* threads, splitting its
arguments into equal-sized chunks.
"""
def func_mt(*args):
length = len(args[0])
result = np.empty(length, dtype=np.float64)
args = (result,) + args
chunklen = (length + numthreads - 1) // numthreads
# Create argument tuples for each input chunk
chunks = [[arg[i * chunklen:(i + 1) * chunklen] for arg in args]
for i in range(numthreads)]
# Spawn one thread per chunk
threads = [threading.Thread(target=inner_func, args=chunk)
for chunk in chunks]
for thread in threads:
thread.start()
for thread in threads:
thread.join()
return result
return func_mt
func_nb = make_singlethread(inner_func_nb)
func_nb_mt = make_multithread(inner_func_nb, nthreads)
a = np.random.rand(size)
b = np.random.rand(size)
correct = timefunc(None, "numpy (1 thread)", func_np, a, b)
timefunc(correct, "numba (1 thread)", func_nb, a, b)
timefunc(correct, "numba (%d threads)" % nthreads, func_nb_mt, a, b)
```
\ No newline at end of file
# 1.18。会谈和教程
> 原文: [http://numba.pydata.org/numba-doc/latest/user/talks.html](http://numba.pydata.org/numba-doc/latest/user/talks.html)
注意
这是 Numba 团队成员和 Numba 用户提供的精选讲座和教程。如果您知道应该包含在此列表中的与 Numba 相关的演讲,请[打开一个问题](https://github.com/numba/numba/issues)
## 1.18.1。谈论 Numba
* AnacondaCON 2018 - 用 Numba 加速科学工作量 - Siu Kwan Lam([视频](https://www.youtube.com/watch?v=6oXedk2tGfk)
* [DIANA-HEP 会议,2018 年 4 月 23 日](https://indico.cern.ch/event/709711/) - Numba 概述 - Stan Seibert
## 1.18.2。谈谈 Numba 的应用
* PyData Berlin 2018 - 使用 Apache Arrow 和 Numba 扩展熊猫 - Uwe L. Korn([视频](https://www.youtube.com/watch?v=tvmX8YAFK80)[博客](https://uwekorn.com/2018/08/03/use-numba-to-work-with-apache-arrow-in-pure-python.html)
* SciPy 2018 - UMAP:均匀流形逼近和尺寸缩小投影 - Leland McInnes([视频](https://www.youtube.com/watch?v=nq6iPZVUxZU)[Github](https://github.com/lmcinnes/umap)
* 2016 年 GPU 技术大会 - 在 GPU 上使用 Python / Numba 加速等离子体物理的光谱算法 - Manuel Kirchen&amp;雷米·勒赫([幻灯片](http://on-demand.gputechconf.com/gtc/2016/presentation/s6353-manuel-kirchen-spectral-algorithm-plasma-physics.pdf)
* [DIANA-HEP 会议,2018 年 4 月 23 日](https://indico.cern.ch/event/709711/) - 在 XENONnT 中使用 Numba - Chris Tunnell
* [DIANA-HEP 会议,2018 年 4 月 23 日](https://indico.cern.ch/event/709711/) - 为 HEP 数据类型扩展 Numba - Jim Pivarski
* STAC 峰会,2017 年 11 月 1 日 - 以最小的努力扩展高性能 Python - Ehsan Totoni([视频](https://stacresearch.com/STAC-Summit-1-Nov-2017-Intel-Totoni)[幻灯片](https://stacresearch.com/system/files/resource/files/STAC-Summit-1-Nov-2017-Intel-Totoni.pdf)
## 1.18.3。教程
* SciPy 2017 - Numba:告诉那些 C ++恶霸失去了 - Gil Forsyth&amp; Lorena Barba([视频](https://www.youtube.com/watch?v=1AwG0T4gaO0)[笔记本](https://github.com/gforsyth/numba_tutorial_scipy2017)
* GPU 技术大会 2018 年 - 使用 Numba 进行 Python 的 GPU 计算 - Stan Seibert([笔记本](https://github.com/ContinuumIO/gtc2018-numba)
\ No newline at end of file
# 2. 参考手册
\ No newline at end of file
# 2.1。类型和签名
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/types.html](http://numba.pydata.org/numba-doc/latest/reference/types.html)
## 2.1.1。理由
作为优化编译器,Numba 需要决定每个变量的类型以生成有效的机器代码。 Python 的标准类型不够精确,所以我们必须开发自己的细粒度类型系统。
在尝试检查 Numba 类型推断的结果时,您会遇到 Numba 类型,用于[调试](envvars.html#numba-envvars)[教育](../developer/architecture.html#architecture)目的。但是,如果提前编译代码 [](../user/pycc.html#pycc) ,则需要显式使用类型。
## 2.1.2。签名
签名指定函数的类型。确切地说允许哪种签名取决于上下文( [AOT](../glossary.html#term-aot)[JIT](../glossary.html#term-jit) 编译),但签名总是涉及 Numba 类型的一些表示,以指定函数参数的具体类型,如果需要,函数的返回类型。
一个示例函数签名是字符串`"f8(i4, i4)"`(或等价的`"float64(int32, int32)"`),它指定一个函数,它接受两个 32 位整数并返回一个双精度浮点数。
## 2.1.3。基本类型
最基本的类型可以通过简单的表达式表达。下面的符号表示主`numba`模块的属性(因此,如果您读取“boolean”,则表示符号可以作为`numba.boolean`访问)。根据 Numpy 的惯例,许多类型都可以作为规范名称和速记别名。
### 2.1.3.1。数字
下表包含 Numba 当前定义的基本数字类型及其别名。
| 输入名称 | 速记 | 评论 |
| --- | --- | --- |
| 布尔 | B1 | 表示为一个字节 |
| uint8,字节 | U1 | 8 位无符号字节 |
| UINT16 | U2 | 16 位无符号整数 |
| UINT32 | U4 | 32 位无符号整数 |
| UINT64 | U8 | 64 位无符号整数 |
| int8,char | I1 | 8 位有符号字节 |
| INT16 | I2 | 16 位有符号整数 |
| INT32 | I4 | 32 位有符号整数 |
| Int64 的 | I8 | 64 位有符号整数 |
| INTC | - | C int 大小的整数 |
| uintc | - | C int 大小的无符号整数 |
| INTP | - | 指针大小的整数 |
| uintp | - | 指针大小的无符号整数 |
| FLOAT32 | F4 | 单精度浮点数 |
| float64,double | F8 | 双精度浮点数 |
| complex64 | C8 | 单精度复数 |
| complex128 | C16 | 双精度复数 |
### 2.1.3.2。数组
声明数组类型的简单方法是根据维数来下标基本类型。例如,一维单精度数组:
```py
>>> numba.float32[:]
array(float32, 1d, A)
```
或相同底层类型的三维数组:
```py
>>> numba.float32[:, :, :]
array(float32, 3d, A)
```
此语法定义没有特定布局的数组类型(生成接受非连续和连续数组的代码),但您可以通过在索引规范的开头或结尾使用`::1`索引来指定特定的连续性:
```py
>>> numba.float32[::1]
array(float32, 1d, C)
>>> numba.float32[:, :, ::1]
array(float32, 3d, C)
>>> numba.float32[::1, :, :]
array(float32, 3d, F)
```
### 2.1.3.3。其他类型
有些非数字类型不适合其他类别。
| 输入名称 | 评论 |
| --- | --- |
| 的 PyObject | 通用 Python 对象 |
| voidptr | 原始指针,不能对它执行任何操作 |
## 2.1.4。高级类型
对于更高级的声明,您必须显式调用 Numba 提供的辅助函数或类。
警告
此处记录的 API 不保证稳定。除非必要,否则建议让 Numba 使用@jit 的[无签名变量来推断参数类型。](../user/jit.html#jit-lazy)
### 2.1.4.1。推论
```py
numba.typeof(value)
```
创建一个 Numba 类型,准确描述给定的 Python _ 值 _。如果 [nopython 模式](../glossary.html#term-nopython-mode)不支持该值,则会引发`ValueError`
```py
>>> numba.typeof(np.empty(3))
array(float64, 1d, C)
>>> numba.typeof((1, 2.0))
(int64, float64)
>>> numba.typeof([0])
reflected list(int64)
```
### 2.1.4.2。 Numpy 标量
除了使用 [`typeof()`](#numba.typeof "numba.typeof") 之外,还可以以编程方式构造诸如结构化类型之类的非平凡标量。
```py
numba.from_dtype(dtype)
```
创建与给定 Numpy _dtype_ 对应的 Numba 类型:
```py
>>> struct_dtype = np.dtype([('row', np.float64), ('col', np.float64)])
>>> ty = numba.from_dtype(struct_dtype)
>>> ty
Record([('row', '<f8'), ('col', '<f8')])
>>> ty[:, :]
unaligned array(Record([('row', '<f8'), ('col', '<f8')]), 2d, A)
```
```py
class numba.types.NPDatetime(unit)
```
为给定 _ 单位 _ 的 Numpy 日期时间创建 Numba 类型。 _ 单位 _ 应该是 Numpy 识别的代码中的一个字符串(例如`Y``M``D`等)。
```py
class numba.types.NPTimedelta(unit)
```
为给定 _ 单位 _ 的 Numpy timedeltas 创建 Numba 类型。 _ 单位 _ 应该是 Numpy 识别的代码中的一个字符串(例如`Y``M``D`等)。
也可以看看
Numpy [日期时间单位](http://docs.scipy.org/doc/numpy/reference/arrays.datetime.html#datetime-units)
### 2.1.4.3。数组
```py
class numba.types.Array(dtype, ndim, layout)
```
创建一个数组类型。 _dtype_ 应该是 Numba 类型。 _ndim_ 是数组的维数(正整数)。 _ 布局 _ 是一个给出数组布局的字符串:`A`表示任何布局,`C`表示 C-contiguous,`F`表示 Fortran-contiguous。
### 2.1.4.4。可选类型
```py
class numba.optional(typ)
```
根据底层 Numba 类型 _typ_ 创建一个可选类型。可选类型将允许 _typ_ 或`None`的任何值。
```py
>>> @jit((optional(intp),))
... def f(x):
... return x is not None
...
>>> f(0)
True
>>> f(None)
False
```
\ No newline at end of file
# 2.2。即时编译
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/jit-compilation.html](http://numba.pydata.org/numba-doc/latest/reference/jit-compilation.html)
## 2.2.1。 JIT 函数
```py
@numba.jit(signature=None, nopython=False, nogil=False, cache=False, forceobj=False, parallel=False, error_model='python', fastmath=False, locals={})
```
即时编译修饰函数以生成高效的机器代码。所有参数都是可选的。
如果存在,_ 签名 _ 是单个签名或表示函数参数和返回值的预期[类型和签名](types.html#numba-types)的签名列表。每个签名可以以多种形式给出:
* [类型和签名](types.html#numba-types)参数(例如`(numba.int32, numba.double)`)的元组,表示函数参数的类型;然后,Numba 将从参数中推断出适当的返回类型。
* 使用[类型和签名](types.html#numba-types)的呼叫签名,指定返回类型和参数类型。这可以以直观的形式给出(例如`numba.void(numba.int32, numba.double)`)。
* 上述之一的字符串表示,例如`"void(int32, double)"`。假定在`numba.types`模块中定义字符串中使用的所有类型名称。
_nopython_ 和 _nogil_ 是布尔标志。 _locals_ 是局部变量名称到[类型和签名](types.html#numba-types)的映射。
这个装饰器有几种操作模式:
* 如果在 _ 签名 _ 中给出一个或多个签名,则为它们中的每一个编译专门化。然后调用修饰函数将尝试选择最佳匹配签名,如果函数参数没有适当的转换,则引发 [`TypeError`](https://docs.python.org/3/library/exceptions.html#TypeError "(in Python v3.7)") 。如果转换成功,则使用转换的参数执行编译的机器代码,并根据签名转换返回值。
* 如果没有给出 _ 签名 _,则修饰函数实现延迟编译。每次对装饰函数的调用都会尝试重用现有的特化(如果存在)(例如,带有两个整数参数的调用可能会重用参数类型`(numba.int64, numba.int64)`的特化)。如果不存在合适的特化,则会即时编译新的特化,存储以供以后使用,并使用转换的参数执行。
如果为 true, _nopython_ 强制在 [nopython 模式](../glossary.html#term-nopython-mode)中编译该函数。如果不可能,编译将引发错误。
如果为真, _forceobj_ 强制在[对象模式](../glossary.html#term-object-mode)中编译该函数。由于对象模式比 nopython 模式慢,因此这对于测试目的非常有用。
如果为 true, _nogil_ 会尝试在编译函数内释放[全局解释器锁](https://docs.python.org/3/glossary.html#term-global-interpreter-lock "(in Python v3.7)")。只有当 Numba 能够在 [nopython 模式](../glossary.html#term-nopython-mode)中编译函数时才会释放 GIL,否则将打印编译警告。
如果为 true,则 _cache_ 允许基于文件的缓存在前一次调用中编译该函数时缩短编译时间。缓存保存在包含源文件的目录的`__pycache__`子目录中;但是,如果不允许当前用户写入它,则它会回退到特定于平台的用户范围的缓存目录(例如 Unix 平台上的`$HOME/.cache/numba`)。
如果为真,则 _parallel_ 启用多个常见 Numpy 构造的自动并行化以及相邻并行操作的融合,以最大化缓存局部性。
_error_model_ 选项控制被零除的行为。将它设置为'python'会导致被零除以引发像 CPython 这样的异常。将其设置为'numpy'会导致被零除以将结果设置为 _+/- inf_ 或 _nan_ 。
并非所有函数都可以缓存,因为某些功能无法始终保留到磁盘。当无法缓存函数时,会发出警告;使用 [`NUMBA_WARNINGS`](envvars.html#envvar-NUMBA_WARNINGS) 查看。
如果为真, _fastmath_ 允许使用 [LLVM 文档](https://llvm.org/docs/LangRef.html#fast-math-flags)中描述的其他不安全的浮点变换。此外,如果[英特尔 SVML](../user/performance-tips.html#intel-svml) 的安装速度更快,但使用的数学内在函数的版本不太准确(`4 ULP`内的答案)。
_locals_ 字典可用于强制特定局部变量的[类型和签名](types.html#numba-types),例如,如果您想在某个时刻强制使用单精度浮点数。通常,我们建议您让 Numba 的编译器自己推断局部变量的类型。
以下是两个签名的示例:
```py
@jit(["int32(int32)", "float32(float32)"], nopython=True)
def f(x): ...
```
在装饰器之后没有放任何括号等同于在没有任何参数的情况下调用装饰器,即:
```py
@jit
def f(x): ...
```
相当于:
```py
@jit()
def f(x): ...
```
装饰器返回 [`Dispatcher`](#Dispatcher "Dispatcher") 对象。
注意
如果没有给出 _ 签名 _,则在实际编译发生时,即首次使用某些给定的参数类型调用函数时,将引发编译错误。
注意
编译可能受某些专用[环境变量](envvars.html#numba-envvars)的影响。
## 2.2.2。生成的 JIT 函数
```py
@numba.generated_jit(nopython=False, nogil=False, cache=False, forceobj=False, locals={})
```
[`jit()`](#numba.jit "numba.jit") 装饰器一样,但是在编译时调用装饰函数,传递函数参数的 _ 类型 _。修饰函数必须返回一个可调用函数,该函数将被编译为函数对这些类型的实现,允许灵活的专业化类型。
[`generated_jit()`](#numba.generated_jit "numba.generated_jit") 装饰器返回 [`Dispatcher`](#Dispatcher "Dispatcher") 对象。
## 2.2.3。调度程序对象
```py
class Dispatcher
```
通过调用 [`jit()`](#numba.jit "numba.jit")[`generated_jit()`](#numba.generated_jit "numba.generated_jit") 创建的对象类。您不应该尝试以任何其他方式创建此类对象。调用 Dispatcher 对象会为调用它的参数调用已编译的特化,使其充当已编译的 Python 函数的加速替换。
此外,Dispatcher 对象具有以下方法和属性:
```py
py_func
```
编译的纯 Python 函数。
```py
inspect_types(file=None, pretty=False)
```
打印出与相应的 Numba IR 一起逐行注释的函数源代码列表,以及各种变量的推断类型。如果指定了 _ 文件 _,则对该文件对象进行打印,否则对 sys.stdout 进行打印。如果 _ 漂亮 _ 设置为 True,那么将在终端和笔记本中的 HTML 中生成彩色 ANSI。
也可以看看
[Numba 架构](../developer/architecture.html#architecture)
```py
inspect_llvm(signature=None)
```
返回将编译的函数签名键入到为函数生成的人类可读 LLVM IR 的字典。如果指定了签名关键字,则返回与该单个签名对应的字符串。
```py
inspect_asm(signature=None)
```
返回将编译的函数签名键入到该函数的人类可读的本机汇编程序代码的字典。如果指定了签名关键字,则返回与该单个签名对应的字符串。
```py
inspect_cfg(signature=None, show_wrapped)
```
返回将编译的函数签名键入到函数的控制流图形对象的字典。如果指定了签名关键字,则返回与该单个签名对应的字符串。
可以对控制流图形对象进行字符串化(`str``repr`)以获得 DOT 格式的图形的文本表示。或者,使用其`.display(filename=None, view=False)`方法绘制图形。可以将 _ 文件名 _ 选项设置为要写入的呈现输出的特定路径。如果 _ 视图 _ 选项为 True,则图形格式(PDF)的系统默认应用程序将打开该图。在 IPython 笔记本中,返回的对象可以是内联图。
用法:
```py
@jit
def foo():
...
# opens the CFG in system default application
foo.inspect_cfg(foo.signatures[0]).display(view=True)
```
```py
recompile()
```
重新编译所有现有签名。这可能很有用,例如,如果函数冻结了全局变量或闭包变量,并且 Python 中的值已更改。由于编译并不便宜,因此主要用于测试和交互式使用。
```py
parallel_diagnostics(signature=None, level=1)
```
打印给定签名的并行诊断信息。如果没有签名,则打印所有已知签名。 `level`用于调整详细程度,`level=1`(默认值)是最小详细程度,2,3 和 4 级提供更高级别的详细程度。
```py
get_metadata(signature=None)
```
获取给定签名的编译元数据。这对于 Numba 和 Numba 扩展的开发人员非常有用。
## 2.2.4。矢量化函数(ufuncs 和 DUFuncs)
```py
@numba.vectorize(*, signatures=[], identity=None, nopython=True, target='cpu', forceobj=False, cache=False, locals={})
```
编译装饰函数并将其包装为 [Numpy ufunc](http://docs.scipy.org/doc/numpy/reference/ufuncs.html) 或 Numba [`DUFunc`](#numba.DUFunc "numba.DUFunc") 。可选的 _nopython_ , _forceobj_ 和 _locals_ 参数具有与 [`numba.jit()`](#numba.jit "numba.jit") 相同的含义。
_ 签名 _ 是一个可选的签名列表,以与 [`numba.jit()`](#numba.jit "numba.jit") _ 签名 _ 参数相同的形式表示。如果 _ 签名 _ 非空,那么装饰器会将用户 Python 函数编译为 Numpy ufunc。如果没有给出 _ 签名 _,那么装饰器会将用户 Python 函数包装在 [`DUFunc`](#numba.DUFunc "numba.DUFunc") 实例中,只要 Numpy 找不到匹配项,它就会在调用时编译用户函数循环输入参数。如果 _ 目标 _ 是`"parallel"`,则需要 _ 签名 _。
_ 标识 _ 是正在实现的函数的标识(或单位)值。可能的值为 0,1,None 和字符串`"reorderable"`。默认值为 None。 None 和`"reorderable"`均表示该函数没有标识值; `"reorderable"`另外指定沿多个轴的减少可以重新排序。
如果有多个 _ 签名 _,则必须从更具体到最不具体的顺序进行排序。否则,Numpy 基于类型的调度可能无法按预期工作。例如,以下是错误的:
```py
@vectorize(["float64(float64)", "float32(float32)"])
def f(x): ...
```
因为在单精度数组上运行它将选择编译函数的`float64`版本,导致执行效率低得多。正确的调用是:
```py
@vectorize(["float32(float32)", "float64(float64)"])
def f(x): ...
```
_target_ 是后端目标的字符串;可用值为“cpu”,“parallel”和“cuda”。要使用多线程版本,请将目标更改为“parallel”(这需要指定签名):
```py
@vectorize(["float64(float64)", "float32(float32)"], target='parallel')
def f(x): ...
```
对于 CUDA 目标,请使用“cuda”:
```py
@vectorize(["float64(float64)", "float32(float32)"], target='cuda')
def f(x): ...
```
可以缓存已编译的函数以减少将来的编译时间。通过将 _ 缓存 _ 设置为 True 来启用它。只有“cpu”和“parallel”目标支持缓存。
```py
@numba.guvectorize(signatures, layout, *, identity=None, nopython=True, target='cpu', forceobj=False, cache=False, locals={})
```
[`numba.vectorize()`](#numba.vectorize "numba.vectorize") 的广义版本。虽然 [`numba.vectorize()`](#numba.vectorize "numba.vectorize") 将产生一个简单的 ufunc,其核心功能(你正在装饰的功能)在标量操作数上运行并返回一个标量值, [`numba.guvectorize()`](#numba.guvectorize "numba.guvectorize") 允许你创建一个 [Numpy ufunc](http://docs.scipy.org/doc/numpy/reference/ufuncs.html) ,其核心功能采用各种维度的数组参数。
附加参数 _layout_ 是一个字符串,以符号形式指定参数类型和返回类型的维度和大小关系。例如,矩阵乘法的布局字符串为`"(m,n),(n,p)-&gt;(m,p)"`。它的定义可能是(函数体省略):
```py
@guvectorize(["void(float64[:,:], float64[:,:], float64[:,:])"],
"(m,n),(n,p)->(m,p)")
def f(a, b, result):
"""Fill-in *result* matrix such as result := a * b"""
...
```
如果其中一个参数应该是标量,则相应的布局规范是`()`,并且该参数将真正作为零维数组给出(您必须取消引用它才能获得标量值)。例如,具有可参数窗口宽度的[一维移动平均值](../user/examples.html#example-movemean)可以具有`"(n),()-&gt;(n)"`的布局串。
请注意,任何输出都将作为附加函数参数预先分配给您:您的代码必须使用您正在实现的函数的适当值填充它。
如果您的函数没有输出数组,则应省略布局字符串中的“箭头”(例如`"(n),(n)"`)。
也可以看看
Numpy 支持的[布局字符串](http://docs.scipy.org/doc/numpy/reference/c-api.generalized-ufuncs.html#details-of-signature)的规范。请注意,Numpy 使用术语“签名”,我们不幸地将其用于其他内容。
可以缓存已编译的函数以减少将来的编译时间。通过将 _ 缓存 _ 设置为 True 来启用它。只有“cpu”和“parallel”目标支持缓存。
```py
class numba.DUFunc
```
通过调用没有签名的 [`numba.vectorize()`](#numba.vectorize "numba.vectorize") 创建的对象类。
DUFunc 实例应该与 Numpy `ufunc`对象的行为类似,但有一个重要区别:调用时循环生成。当调用 ufunc 时,Numpy 会查看为该 ufunc 注册的现有循环,并且如果找不到一个无法安全地投射输入以适应的循环,则会引发`TypeError`。当呼叫 DUFunc 时,Numba 将呼叫委托给 Numpy。如果 Numpy ufunc 调用失败,那么 Numba 会尝试为给定的输入类型构建一个新循环,并再次调用 ufunc。如果第二次调用尝试失败或发生编译错误,则 DUFunc 将异常传递给调用者。
也可以看看
用户指南中的“[动态通用函数](../user/vectorize.html#dynamic-universal-functions)”部分演示了 [`DUFunc`](#numba.DUFunc "numba.DUFunc") 的调用时间行为,并讨论了调用顺序对 Numba 如何生成基础`ufunc`的影响。
```py
ufunc
```
实际的 Numpy `ufunc`对象由 [`DUFunc`](#numba.DUFunc "numba.DUFunc") 实例构建。请注意, [`DUFunc`](#numba.DUFunc "numba.DUFunc") 对象维护了正确的 ufunc 功能所需的几个重要数据结构(特别是动态编译的循环)。用户不应传递`ufunc`值而不确保底层 [`DUFunc`](#numba.DUFunc "numba.DUFunc") 不会被垃圾收集。
```py
nin
```
DUFunc(ufunc)输入的数量。见 [ufunc.nin](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.nin.html#numpy.ufunc.nin)
```py
nout
```
DUFunc 输出的数量。见 [ufunc.nout](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.nout.html#numpy.ufunc.nout)
```py
nargs
```
可能的 DUFunc 参数总数(应为 [`nin`](#numba.DUFunc.nin "numba.DUFunc.nin") + [`nout`](#numba.DUFunc.nout "numba.DUFunc.nout") )。见 [ufunc.nargs](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.nargs.html#numpy.ufunc.nargs)
```py
ntypes
```
DUFunc 支持的输入类型数。见 [ufunc.ntypes](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.ntypes.html#numpy.ufunc.ntypes)
```py
types
```
以字符串形式提供的受支持类型的列表。见 [ufunc.types](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.types.html#numpy.ufunc.types)
```py
identity
```
使用 ufunc 作为缩减时的标识值。见 [ufunc.identity](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.identity.html#numpy.ufunc.identity)
```py
reduce(A, *, axis, dtype, out, keepdims)
```
通过沿一个轴应用 DUFunc,将 _A_ 的尺寸减一。见 [ufunc.reduce](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.reduce.html#numpy.ufunc.reduce)
```py
accumulate(A, *, axis, dtype, out)
```
累积将运算符应用于所有元素的结果。见 [ufunc.accumulate](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.accumulate.html#numpy.ufunc.accumulate)
```py
reduceat(A, indices, *, axis, dtype, out)
```
在单个轴上使用指定切片执行(局部)缩减。见 [ufunc.reduceat](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.reduceat.html#numpy.ufunc.reduceat)
```py
outer(A, B)
```
将 ufunc 应用于所有对( _a_ , _b_ )与 _a_ 在 _A_ 和 _b_ 中 _B_ 。见 [ufunc.outer](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.outer.html#numpy.ufunc.outer)
```py
at(A, indices, *, B)
```
对 _ 索引 _ 指定的元素在操作数 _A_ 上执行无缓冲就位操作。如果您使用的是 Numpy 1.7 或更早版本,则此方法将不存在。见 [ufunc.at](http://docs.scipy.org/doc/numpy/reference/generated/numpy.ufunc.at.html#numpy.ufunc.at)
注意
在极少数情况下,矢量化函数可能会显示[意外警告或错误](fpsemantics.html#ufunc-fpu-errors)
## 2.2.5。 C 回调
```py
@numba.cfunc(signature, nopython=False, cache=False, locals={})
```
即时编译修饰函数以生成高效的机器代码。编译后的代码包含在一个瘦 C 回调中,使得它可以使用自然的 C ABI 进行调用。
_ 签名 _ 是表示 C 回调签名的单个签名。它必须与 [`jit()`](#numba.jit "numba.jit") 中的形式相同。装饰器不会检查签名中的类型是否在 C 中具有明确定义的表示。
_nopython_ 和 _ 缓存 _ 是布尔标志。 _locals_ 是局部变量名称到[类型和签名](types.html#numba-types)的映射。它们都与 [`jit()`](#numba.jit "numba.jit") 中的含义相同。
装饰器返回 [`CFunc`](#CFunc "CFunc") 对象。
注意
C 回调目前不支持[对象模式](../glossary.html#term-object-mode)
```py
class CFunc
```
[`cfunc()`](#numba.cfunc "numba.cfunc") 创建的对象类。 [`CFunc`](#CFunc "CFunc") 对象公开以下属性和方法:
```py
address
```
已编译的 C 回调的地址,为整数。
```py
cffi
```
一个 [cffi](https://cffi.readthedocs.org/) 函数指针实例,作为参数传递给 [cffi](https://cffi.readthedocs.org/) - 包装函数。指针的类型是`void *`,因此只有在将其传递给 [cffi](https://cffi.readthedocs.org/) 时才会进行最小类型检查。
```py
ctypes
```
一个 [`ctypes`](https://docs.python.org/3/library/ctypes.html#module-ctypes "(in Python v3.7)") 回调实例,好像它是使用 [`ctypes.CFUNCTYPE()`](https://docs.python.org/3/library/ctypes.html#ctypes.CFUNCTYPE "(in Python v3.7)") 创建的。
```py
native_name
```
已编译的 C 回调的名称。
```py
inspect_llvm()
```
返回为 C 回调生成的人类可读的 LLVM IR。 [`native_name`](#CFunc.native_name "CFunc.native_name") 是在 IR 中定义此回调的名称。
\ No newline at end of file
# 2.3。提前编译
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/aot-compilation.html](http://numba.pydata.org/numba-doc/latest/reference/aot-compilation.html)
```py
class numba.pycc.CC(extension_name, source_module=None)
```
用于从 Numba 编译的 Python 函数生成编译扩展的对象。 _extension_name_ 是要生成的扩展名。 _source_module_ 是包含这些函数的 Python 模块;如果`None`,则通过检查调用堆栈来推断。
[`CC`](#numba.pycc.CC "numba.pycc.CC") 实例具有以下属性和方法:
```py
name
```
(只读属性)要生成的扩展模块的名称。
```py
output_dir
```
(读写属性)扩展模块将写入的目录。默认情况下,它是 _source_module_ 所在的目录。
```py
output_file
```
(读写属性)扩展模块将写入的文件的名称。默认情况下,这遵循当前平台的 Python 命名约定。
```py
target_cpu
```
(读写属性)为其生成代码的 CPU 模型的名称。这将选择适当的指令集扩展。默认情况下,选择通用 CPU 以生成可移植代码。
此属性的已识别名称取决于当前体系结构和 LLVM 版本。如果安装了 LLVM,`llc -mcpu=help`将为您提供一个列表。 x86-64 的例子是`"ivybridge"``"haswell"``"skylake"``"broadwell"`。您还可以给出值`"host"`,它将选择当前的主机 CPU。
```py
verbose
```
(读写属性)如果为 true,则在编译扩展时打印输出信息。默认为 False。
```py
@export(exported_name, sig)
```
使用签名 _sig_ 标记要编译的修饰函数。编译的函数将在生成的扩展模块中作为 _exported_name_ 公开。
给定 [`CC`](#numba.pycc.CC "numba.pycc.CC") 实例中的所有导出名称必须是不同的,否则会引发异常。
```py
compile()
```
编译所有导出的函数并生成 [`output_dir`](#numba.pycc.CC.output_dir "numba.pycc.CC.output_dir")[`output_file`](#numba.pycc.CC.output_file "numba.pycc.CC.output_file") 指定的扩展模块。
```py
distutils_extension(**kwargs)
```
返回 [`distutils.core.Extension`](https://docs.python.org/3/distutils/apiref.html#distutils.core.Extension "(in Python v3.7)") 实例,允许在传统的`setup.py`驱动的构建过程中集成扩展模块的生成。可选的 _kwargs_ 允许您将可选参数传递给 [`Extension`](https://docs.python.org/3/distutils/apiref.html#distutils.core.Extension "(in Python v3.7)") 构造函数。
在这种操作模式下,没有必要自己调用 [`compile()`](#numba.pycc.CC.compile "numba.pycc.CC.compile") 。此外, [`output_dir`](#numba.pycc.CC.output_dir "numba.pycc.CC.output_dir")[`output_file`](#numba.pycc.CC.output_file "numba.pycc.CC.output_file") 将被忽略。
\ No newline at end of file
# 2.4。公用事业
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/utils.html](http://numba.pydata.org/numba-doc/latest/reference/utils.html)
## 2.4.1。处理指针
这些函数可以从纯 Python 以及 [nopython 模式](../glossary.html#term-nopython-mode)中调用。
```py
numba.carray(ptr, shape, dtype=None)
```
以[C]顺序返回具有给定 _ 形状 _ 的 _ptr_ 指向的数据的 Numpy 数组视图。如果给出 _dtype_ ,则将其用作数组的 dtype,否则从 _ptr_ 的类型推断出数组的 dtype。由于返回的数组是视图而不是副本,因此写入它将修改原始数据。
_ptr_ 应该是一个 ctypes 指针对象(使用 [`POINTER()`](https://docs.python.org/3/library/ctypes.html#ctypes.POINTER "(in Python v3.7)")[`c_void_p`](https://docs.python.org/3/library/ctypes.html#ctypes.c_void_p "(in Python v3.7)") 创建的类型指针)。
_shape_ 应该是整数或整数元组。
_dtype_ 应该是 Numpy dtype 或标量类(即`np.dtype('int8')``np.int8`都被接受)。
```py
numba.farray(ptr, shape, dtype=None)
```
[`carray()`](#numba.carray "numba.carray") 相同,但假设数据以 Fortran 顺序排列,并相应地构造数组视图。
\ No newline at end of file
# 2.5。环境变量
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/envvars.html](http://numba.pydata.org/numba-doc/latest/reference/envvars.html)
Numba 允许通过使用环境变量来改变其行为。除非另有说明,否则这些变量具有整数值且默认为零。
为方便起见,Numba 还支持使用配置文件来保留配置设置。注意:要使用此功能,必须安装`pyyaml`
配置文件必须命名为`.numba_config.yaml`并存在于调用 Python 解释器的目录中。在搜索环境变量之前,将读取配置文件(如果存在)以进行配置设置。这意味着环境变量设置将覆盖从配置文件获取的设置(配置文件用于设置永久首选项,而环境变量用于短暂首选项)。
配置文件的格式是`YAML`格式的字典,它将下面的环境变量(没有`NUMBA_`前缀)映射到所需的值。例如,要永久打开开发人员模式(`NUMBA_DEVELOPER_MODE`环境变量)并控制流程图打印(`NUMBA_DUMP_CFG`环境变量),请创建一个包含以下内容的配置文件:
```py
developer_mode: 1
dump_cfg: 1
```
在想要使用基于终端背景颜色的设定颜色方案的情况下,这尤其有用。例如,如果终端背景颜色为黑色,则`dark_bg`颜色方案将非常适合,并且可以通过添加以下内容设置为永久使用:
```py
color_scheme: dark_bg
```
## 2.5.1。错误和警告显示
```py
NUMBA_WARNINGS
```
如果设置为非零,则启用 Numba 警告的打印输出,否则将禁止警告。警告可以深入了解编译过程。
## 2.5.2。调试
这些变量会影响 [JIT 函数](../glossary.html#term-jit-function)编译过程中打印的内容。
```py
NUMBA_DEVELOPER_MODE
```
如果设置为非零,则开发人员模式会生成完整的回溯并禁用帮助说明。默认值为零。
```py
NUMBA_FULL_TRACEBACKS
```
如果设置为非零,则在发生异常时启用完全回溯。默认为 &lt;cite&gt;NUMBA_DEVELOPER_MODE&lt;/cite&gt; 设置的值。
```py
NUMBA_SHOW_HELP
```
如果未设置或设置为零,则显示用户级帮助信息。默认为 &lt;cite&gt;NUMBA_DEVELOPER_MODE&lt;/cite&gt; 设置的值的否定。
```py
NUMBA_DISABLE_ERROR_MESSAGE_HIGHLIGHTING
```
如果设置为非零错误消息突出显示被禁用。这对于在 CI 系统上运行测试套件非常有用。
```py
NUMBA_COLOR_SCHEME
```
更改错误报告中使用的颜色方案(需要安装`colorama`包才能工作)。有效值为:
* `no_color`没有添加颜色,只是粗体字体加权。
* `dark_bg`适用于背景较暗的终端。
* `light_bg`适用于背景较浅的终端。
* `blue_bg`适用于蓝色背景的终端。
* `jupyter_nb`适用于 Jupyter 笔记本电脑。
_ 默认值:_ `no_color`。值的类型是`string`
```py
NUMBA_DEBUG
```
如果设置为非零,则在函数编译期间打印出所有可能的调试信息。使用下面的其他变量可以获得更细粒度的控制。
```py
NUMBA_DEBUG_FRONTEND
```
如果设置为非零,则在编译器前端的操作期间打印出调试信息,直到并包括 Numba 中间表示的生成。
```py
NUMBA_DEBUGINFO
```
如果设置为非零,则通过设置`jit``debug`选项的默认值,为整个应用程序启用调试。请注意,启用调试信息会显着增加每个已编译函数的内存消耗。默认值等于 &lt;cite&gt;NUMBA_ENABLE_PROFILING&lt;/cite&gt; 的值。
```py
NUMBA_GDB_BINARY
```
设置`gdb`二进制文件以用于 Numba 的`gdb`支持,它采用路径和二进制文件的全名,例如:`/path/from/root/to/binary/name_of_gdb_binary`这是为了允许使用来自非 COD3 的`gdb`具有非默认名称的默认位置。如果未设置,则假定`gdb`位于`/usr/bin/gdb`
```py
NUMBA_DEBUG_TYPEINFER
```
如果设置为非零,则打印出有关类型推断的调试信息。
```py
NUMBA_DEBUG_CACHE
```
如果设置为非零,则打印出有关 [JIT 编译缓存](../user/jit.html#jit-cache)操作的信息。
```py
NUMBA_ENABLE_PROFILING
```
启用 LLVM 的 JIT 事件以支持 jitted 函数的分析。某些分析器下会自动启用此选项。
```py
NUMBA_TRACE
```
如果设置为非零,则跟踪某些函数调用(函数入口和出口事件,包括参数和返回值)。
```py
NUMBA_DUMP_BYTECODE
```
如果设置为非零,则打印出已编译函数的 Python [字节码](../glossary.html#term-bytecode)
```py
NUMBA_DUMP_CFG
```
如果设置为非零,则打印出有关已编译函数的控制流图的信息。
```py
NUMBA_DUMP_IR
```
如果设置为非零,则打印出已编译函数的 Numba Intermediate Representation。
```py
NUMBA_DUMP_ANNOTATION
```
如果设置为非零,则打印出已编译函数的类型注释。
```py
NUMBA_DUMP_LLVM
```
转储未经优化的 LLVM 汇编程序编译函数源。未经优化的代码通常非常冗长;因此,建议改用 [`NUMBA_DUMP_OPTIMIZED`](#envvar-NUMBA_DUMP_OPTIMIZED)
```py
NUMBA_DUMP_FUNC_OPT
```
在 LLVM“函数优化”通过之后但在“模块优化”通过之前转储 LLVM 汇编程序源。这在开发 Numba 本身时很有用,否则使用 [`NUMBA_DUMP_OPTIMIZED`](#envvar-NUMBA_DUMP_OPTIMIZED)
```py
NUMBA_DUMP_OPTIMIZED
```
在所有优化过程之后转储已编译函数的 LLVM 汇编器源。输出包括 raw 函数以及与 CPython 兼容的包装器(其名称以`wrapper.`开头)。请注意,该函数通常也会在包装器内部内联。
```py
NUMBA_DEBUG_ARRAY_OPT
```
转储与`parallel=True` jit 装饰器选项相关的处理相关的调试信息。
```py
NUMBA_DEBUG_ARRAY_OPT_RUNTIME
```
转储与`parallel=True` jit 装饰器选项关联的运行时调度程序相关的调试信息。
```py
NUMBA_DEBUG_ARRAY_OPT_STATS
```
转储有关将多少个运算符/调用转换为并行 for 循环以及多少融合在一起的统计信息,这些都与`parallel=True` jit 装饰器选项相关联。
```py
NUMBA_PARALLEL_DIAGNOSTICS
```
如果设置为 1 到 4(包括 1 和 4)之间的整数值,Numba 进行的并行变换的诊断信息将写入 STDOUT。值越高,产生的信息越详细。
```py
NUMBA_DUMP_ASSEMBLY
```
转储已编译函数的本机汇编代码。
也可以看看
[故障排除和提示](../user/troubleshoot.html#numba-troubleshooting)[Numba 架构](../developer/architecture.html#architecture)
## 2.5.3。编译选项
```py
NUMBA_OPT
```
优化水平;此选项直接传递给 LLVM。
_ 默认值:_ 3
```py
NUMBA_LOOP_VECTORIZE
```
如果设置为非零,则启用 LLVM 循环向量化。
_ 默认值:_ 1(32 位 Windows 除外)
```py
NUMBA_ENABLE_AVX
```
如果设置为非零,则在 LLVM 中启用 AVX 优化。默认情况下,Sandy Bridge 和 Ivy Bridge 架构禁用此功能,因为它有时会导致这些平台上的代码速度变慢。
```py
NUMBA_DISABLE_INTEL_SVML
```
如果设置为非零且 Intel SVML 可用,则将禁用 SVML。
```py
NUMBA_COMPATIBILITY_MODE
```
如果设置为非零,则 JIT 函数的编译永远不会完全失败,而是生成一个简单地解释函数的回退。只有在从旧的 Numba 版本(0.12 之前)迁移大型代码库时才能使用它,并希望避免一次性破坏所有内容。否则,请不要使用它。
```py
NUMBA_DISABLE_JIT
```
完全禁用 JIT 编译。 [`jit()`](jit-compilation.html#numba.jit "numba.jit") 装饰器就像它不执行任何操作一样,并且装饰函数的调用调用原始 Python 函数而不是编译版本。如果要在代码上运行 Python 调试器,这可能很有用。
```py
NUMBA_CPU_NAME and NUMBA_CPU_FEATURES
```
覆盖 CPU 和 CPU 功能检测。通过设置`NUMBA_CPU_NAME=generic`,将为 CPU 体系结构选择通用 CPU 模型,并且功能列表(`NUMBA_CPU_FEATURES`)默认为空。必须以`+feature1,-feature2`格式列出 CPU 功能,其中`+`表示启用,`-`表示禁用。例如,`+sse,+sse2,-avx,-avx2`启用 SSE 和 SSE2,并禁用 AVX 和 AVX2。
这些设置将传递给 LLVM 以配置编译目标。要获取可用选项列表,请使用 LLVM 中的`llc`命令行工具,例如:
```py
llc -march=x86 -mattr=help
```
小费
要强制所有缓存函数(`@jit(cache=True)`)发出可移植代码(在同一架构和操作系统中可移植),只需设置`NUMBA_CPU_NAME=generic`即可。
```py
NUMBA_FUNCTION_CACHE_SIZE
```
覆盖函数高速缓存的大小,以便在内存中保留最近反序列化的函数。在像 [Dask](http://dask.pydata.org) 这样的系统中,通常会对函数进行多次反序列化。只要解释器​​中有某个引用,Numba 就会缓存函数。此高速缓存大小变量控制将保留不再引用的函数的数量,以防它们将来出现。这种实现并不是真正的 LRU,但是对于大多数情况来说,大尺寸的缓存应该足够了。
_ 默认值:_ 128
## 2.5.4。 GPU 支持
```py
NUMBA_DISABLE_CUDA
```
如果设置为非零,则禁用 CUDA 支持。
```py
NUMBA_FORCE_CUDA_CC
```
如果设置,则强制 CUDA 计算功能为给定版本(类型为`major.minor`的字符串),而不考虑连接的设备。
```py
NUMBA_ENABLE_CUDASIM
```
如果设置,请不要编译和执行 GPU 的代码,而是使用 CUDA Simulator。用于调试目的。
## 2.5.5。线程控制
```py
NUMBA_NUM_THREADS
```
如果设置,则并行 CPU 目标的线程池中的线程数将采用此值。必须大于零。该值与`OMP_NUM_THREADS``MKL_NUM_THREADS`无关。
_ 默认值:_ 运行时确定的系统 CPU 核心数,可通过`numba.config.NUMBA_DEFAULT_NUM_THREADS`访问。
```py
NUMBA_THREADING_LAYER
```
此环境变量控制用于 CPU 并行目标(`@vectorize(target='parallel')``@guvectorize(target='parallel')``@njit(parallel=True)`)的并发执行的库。变量类型是字符串,默认情况下是`default`,它将根据运行时中可用的内容选择线程层。有效值为(有关这些的更多信息,请参见[线程层文档](../user/threading-layer.html#numba-threading-layer)):
* `default` - 根据当前运行时可用的内容选择线程层。
* `safe` - 选择一个既安全又安全的线程层(需要 TBB 包)。
* `forksafe` - 选择叉安全的线程层。
* `threadsafe` - 选择线程安全的线程层。
* `tbb` - 由英特尔 TBB 支持的线程层。
* `omp` - 由 OpenMP 支持的线程层。
* `workqueue` - 一个简单的内置工作共享任务调度程序。
\ No newline at end of file
此差异已折叠。
此差异已折叠。
# 2.8。与 Python 语义的偏差
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/pysemantics.html](http://numba.pydata.org/numba-doc/latest/reference/pysemantics.html)
## 2.8.1。异常和内存分配
由于当前编译器在处理异常时的限制,在引发异常的函数中分配的内存(几乎总是 NumPy 数组)将**泄漏**。这是一个已修复的已知问题,但与此同时,最好在函数之外进行内存分配,这也可能引发异常。
## 2.8.2。整数宽度
虽然 Python 具有任意大小的整数,但 Numba 编译函数中的整数通过[类型推断](../glossary.html#term-type-inference)(通常是机器整数的大小)获得固定大小。这意味着算术运算可以包围或产生未定义的结果或溢出。
可以通过显式类型规范覆盖类型推断,期望对整数宽度进行细粒度控制。
也可以看看
[增强建议 1:整数输入的变化](../proposals/integer-typing.html#nbep-1)
## 2.8.3。布尔反转
在 Python boolean 上调用按位补码运算符(`~`运算符)返回一个整数,而 Numpy 布尔值上的相同运算符返回另一个布尔值:
```py
>>> ~True
-2
>>> ~np.bool_(True)
False
```
Numba 遵循 Numpy 语义。
## 2.8.4。全局和闭包变量
[nopython 模式](../glossary.html#term-nopython-mode)中,Numba 的全局和闭包变量是 _ 冻结 _:Numba 编译的函数在编译函数时看到这些变量的值。此外,无法从功能更改其值。
Numba **可能会或可能不会**复制已编译函数内引用的全局变量。通过不变性假设复制小的全局数组以进行潜在的编译器优化。但是,不会复制大型全局数组以节省内存。 “小”和“大”的定义可能会改变。
去做
该文件需要完成。
\ No newline at end of file
# 2.9。浮点陷阱
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/fpsemantics.html](http://numba.pydata.org/numba-doc/latest/reference/fpsemantics.html)
## 2.9.1。精度和准确度
对于某些操作,Numba 可能使用与 Python 或 Numpy 不同的算法。结果可能不是逐位兼容的。差异通常应该很小并且在合理的期望范围内。但是,小的累积差异最终可能会产生很大的差异,特别是如果涉及不同的功能。
### 2.9.1.1。数学库实现
Numba 支持各种平台和操作系统,每个平台和操作系统都有自己的数学库实现(此处称为`libm`)。 `libm`中包含的大多数数学函数都有 IEEE 754 标准规定的特定要求(如`sin()``exp()`等),但每个实现都可能有错误。因此,在某些平台上,Numba 必须特别注意以解决已知的`libm`问题。
另一个典型问题是操作系统的`libm`功能集不完整,需要通过附加功能进行补充。这些参考 IEEE 754 和 C99 标准提供,并且通常以类似于等效 CPython 功能的方式在 Numba 中实现。
特别是,已知数学库问题会影响 Windows 上的 Python 2.7 构建,因为 Python 2.7 需要使用过时版本的 Microsoft Visual Studio 编译器。
### 2.9.1.2。线性代数
即使给出`float32`输入,Numpy 也会强制某些线性代数运算以双精度模式运行。当所有输入都是`float32``complex64`时,Numba 将始终观察输入的精度,并调用单精度线性代数例程。
Numba 中`numpy.linalg`例程的实现仅支持在提供底层核心功能的 LAPACK 函数中使用的浮点类型。因此,仅支持`float32``float64``complex64``complex128`类型。如果用户有例如在`int32`类型中,在用于这些例程之前,必须对浮点类型执行适当的类型转换。这个决定的原因是基本上避免必须复制在 Numpy 中做出的类型转换选择,并且还鼓励用户为他们正在进行的操作选择最佳浮点类型。
### 2.9.1.3。混合型操作
Numpy 最常返回`float64`作为使用混合整数和浮点操作数的计算结果(典型示例是幂运算符`**`)。相比之下,Numba 将在浮点操作数中选择最高精度,因此例如`float32 ** int32`将返回`float32`,而不管输入值如何。这使得性能特征更容易预测,但如果需要额外的精度,则应明确地将输入转换为`float64`
## 2.9.2。警告和错误
当调用 [`vectorize()`](jit-compilation.html#numba.vectorize "numba.vectorize") 创建的 [ufunc](../glossary.html#term-ufunc) 时,Numpy 将通过检查 FPU 错误字来确定是否发生错误。然后它可能会打印出警告或引发异常(例如`RuntimeWarning: divide by zero encountered`),具体取决于当前的错误处理设置。
但是,根据 LLVM 如何优化 ufunc 代码,可能会出现一些虚假警告或错误。如果您遇到此问题,我们建议您调用 [`numpy.seterr()`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.seterr.html#numpy.seterr "(in NumPy v1.16)") 来更改 Numpy 的错误处理设置,或者 [`numpy.errstate`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.errstate.html#numpy.errstate "(in NumPy v1.16)") 上下文管理器暂时切换它们:
```py
with np.errstate(all='ignore'):
x = my_ufunc(y)
```
\ No newline at end of file
# 2.10。 Python 2.7 寿命终止计划
> 原文: [http://numba.pydata.org/numba-doc/latest/reference/python27-eol.html](http://numba.pydata.org/numba-doc/latest/reference/python27-eol.html)
根据 [PEP 373](http://legacy.python.org/dev/peps/pep-0373/) ,Python 2.7 将在 2020 年停止支持,尽管[尚未正式选择](https://pythonclock.org/)。像许多项目一样,Numba 团队必须考虑如何为自己的 Python 2.7 支持提供时间。鉴于 Numba 必须与 Python 解释器进行交互有多深,支持 Python 2 和 3 会产生相当大的开发和测试负担。此外,Numba(特别是通过 llvmlite)必须处理 Windows 上一些特别棘手的编译器问题,其中 LLVM 需要 Visual Studio 2015 或更高版本,但必须使用 Visual Studio 2008 构建 Python 2.7 扩展。不用说,目标是计划是支持我们的 Python 2.7 用户群(截至 2018 年 2 月约 30%的下载量),但也明确表示 _ 现在是时候切换到 Python 3,如果你还没有 _。
Numba 的 Python 2.7 用户也应该知道 [NumPy 结束 Python 2.7 支持](https://github.com/numpy/numpy/blob/master/doc/neps/nep-0014-dropping-python2.7-proposal.rst)的时间表。由于 Numba 与 NumPy 紧密结合,NumPy 时间表强烈告知下面的 Numba 时间表。
## 2.10.1。时间表
Numba 中 Python 2.7 支持的结束将上演:
* **2018 年 12 月**:标记并发布 Numba 1.x.0。基于此版本创建 Python 2.7 分支。
* 关键修复,直到 **2020 年 1 月 1 日**将被移植到 Python 2.7 分支并作为 Numba 1.x.y 发布。
* Python 2.7 分支中不会添加任何新功能,但我们将继续使用新的 NumPy 版本对其进行自动测试。
* **2019 年 1 月 1 日**:我们将通过删除所有 Python 2.7 兼容性代码来减少 Numba master 分支并释放 Numba 1.(x + 1).0,它将在功能上与 Numba 1.x 相同 0.0。
* **2020 年 1 月 1 日**:Numba 开发者将停止支持 Python 2.7 分支。
如果对上述时间表有疑虑,请[在我们的问题跟踪器中提出问题](https://github.com/numba/numba/issues)
\ No newline at end of file
# 3. 用于 CUDA GPU 的 Numba
\ No newline at end of file
# 3.1。概述
> 原文: [http://numba.pydata.org/numba-doc/latest/cuda/overview.html](http://numba.pydata.org/numba-doc/latest/cuda/overview.html)
Numba 通过直接将 CudA 内核和 CUDA 执行模型之后的 CUDA 内核和设备函数的受限子集编译为 CUDA GPU 编程。用 Numba 编写的内核似乎可以直接访问 NumPy 数组。 NumPy 阵列自动在 CPU 和 GPU 之间传输。
## 3.1.1。术语
这里列出了 CUDA 编程主题中的几个重要术语:
* _ 主机 _:CPU
* _ 设备 _:GPU
* _ 主机内存 _:系统主内存
* _ 设备内存 _:GPU 卡上的板载内存
* _ 内核 _:由主机启动并在设备上执行的 GPU 功能
* _ 设备功能 _:在设备上执行的 GPU 功能,只能从设备调用(即从内核或其他设备功能)
## 3.1.2。编程模型
Numba 公开的大多数 CUDA 编程工具都直接映射到 NVidia 提供的 CUDA C 语言。因此,建议您阅读官方 [CUDA C 编程指南](http://docs.nvidia.com/cuda/cuda-c-programming-guide)
## 3.1.3。要求
### 3.1.3.1。支持的 GPU
Numba 支持支持 CUDA 的 GPU,其计算能力为 2.0 或更高,具有最新数据的 Nvidia 驱动程序。
### 3.1.3.2。软件
您将需要安装 CUDA 工具包。如果您使用的是 Conda,只需输入:
```py
$ conda install cudatoolkit
```
## 3.1.4。缺少 CUDA 功能
Numba 尚未实现 CUDA 的所有功能。下面列出了一些缺少的功能:
* 动态并行
* 纹理记忆
\ No newline at end of file
# 3.2。编写 CUDA 内核
> 原文: [http://numba.pydata.org/numba-doc/latest/cuda/kernels.html](http://numba.pydata.org/numba-doc/latest/cuda/kernels.html)
## 3.2.1。简介
与用于编程 CPU 的传统顺序模型不同,CUDA 具有执行模型。在 CUDA 中,您编写的代码将由多个线程同时执行(通常为数百或数千)。您的解决方案将通过定义 _grid_ , _blocks_ 和 _threads_ 的线程层次结构来建模。
Numba 的 CUDA 支持公开了用于声明和管理这种线程层次结构的工具。这些设施与 NVidia 的 CUDA C 语言大致相似。
Numba 还暴露了三种 GPU 内存:全局[设备内存](memory.html#cuda-device-memory)(连接到 GPU 本身的大型,相对较慢的片外内存),片上[共享内存](memory.html#cuda-shared-memory)[]本地记忆](memory.html#cuda-local-memory)。除了最简单的算法外,您必须仔细考虑如何使用和访问内存,以最大限度地减少带宽需求和争用。
## 3.2.2。内核声明
_ 内核函数 _ 是一个 GPU 函数,用于从 CPU 代码(*)调用。它赋予它两个基本特征:
* 内核无法显式返回值;所有结果数据必须写入传递给函数的数组(如果计算一个标量,你可能会传递一个单元素数组);
* 内核在被调用时显式声明它们的线程层次结构:即线程块的数量和每个块的线程数(注意,当内核被编译一次时,可以使用不同的块大小或网格大小多次调用它)。
乍一看,使用 Numba 编写 CUDA 内核看起来非常像为 CPU 编写 [JIT 函数](../glossary.html#term-jit-function)
```py
@cuda.jit
def increment_by_one(an_array):
"""
Increment all array elements by one.
"""
# code elided here; read further for different implementations
```
*)注意:较新的 CUDA 设备支持设备端内核启动;此功能称为 _ 动态并行 _,但 Numba 目前不支持它
## 3.2.3。内核调用
内核通常以以下方式启动:
```py
threadsperblock = 32
blockspergrid = (an_array.size + (threadsperblock - 1)) // threadsperblock
increment_by_one[blockspergrid, threadsperblock](an_array)
```
我们在这里注意两个步骤:
* 通过指定多个块(或“每个网格的块”)以及每个块的多个线程来实例化内核。两者的乘积将给出启动的线程总数。内核实例化是通过编译内核函数(此处为`increment_by_one`)并使用整数元组对其进行索引来完成的。
* 运行内核,通过传递输入数组(以及任何必要的单独输出数组)。默认情况下,运行内核是同步的:当内核完成执行并且数据被同步回来时,函数返回。
### 3.2.3.1。选择块大小
在声明内核所需的线程数时,拥有两级层次结构似乎很奇怪。块大小(即每个块的线程数)通常至关重要:
* 在软件方面,块大小决定共享[共享内存](memory.html#cuda-shared-memory)的给定区域的线程数。
* 在硬件方面,块大小必须足够大才能完全占用执行单元;建议可在 [CUDA C 编程指南](http://docs.nvidia.com/cuda/cuda-c-programming-guide)中找到。
### 3.2.3.2。多维块和网格
为了帮助处理多维数组,CUDA 允许您指定多维块和网格。在上面的示例中,您可以使`blockspergrid``threadsperblock`元组为一个,两个或三个整数。与等效大小的 1D 声明相比,这不会改变生成代码的效率或行为,但可以帮助您以更自然的方式编写算法。
## 3.2.4。螺纹定位
运行内核时,每个线程执行一次内核函数的代码。因此,它必须知道它所在的线程,以便知道它负责哪个数组元素(复杂的算法可能定义更复杂的责任,但基本原理是相同的)。
一种方法是让线程确定它在网格中的位置并阻塞并手动计算相应的数组位置:
```py
@cuda.jit
def increment_by_one(an_array):
# Thread id in a 1D block
tx = cuda.threadIdx.x
# Block id in a 1D grid
ty = cuda.blockIdx.x
# Block width, i.e. number of threads per block
bw = cuda.blockDim.x
# Compute flattened index inside the array
pos = tx + ty * bw
if pos < an_array.size: # Check array boundaries
an_array[pos] += 1
```
注意
除非您确定块大小和网格大小是数组大小的除数,否则**必须**检查边界,如上所示。
[`threadIdx`](../cuda-reference/kernel.html#numba.cuda.threadIdx "numba.cuda.threadIdx")[`blockIdx`](../cuda-reference/kernel.html#numba.cuda.blockIdx "numba.cuda.blockIdx")[`blockDim`](../cuda-reference/kernel.html#numba.cuda.blockDim "numba.cuda.blockDim")[`gridDim`](../cuda-reference/kernel.html#numba.cuda.gridDim "numba.cuda.gridDim") 是 CUDA 后端为鞋底提供的特殊对象了解线程层次结构的几何以及当前线程在该几何中的位置的目的。
这些对象可以是 1D,2D 或 3D,具体取决于内核[调用的方式](#cuda-kernel-invocation)。要访问每个维度的值,请分别使用这些对象的`x``y``z`属性。
```py
numba.cuda.threadIdx
```
当前线程块中的线程索引。对于 1D 块,索引(由`x`属性给出)是一个整数,范围从 0 到包括 [`numba.cuda.blockDim`](../cuda-reference/kernel.html#numba.cuda.blockDim "numba.cuda.blockDim") 不包括。当使用多个维度时,每个维度都存在类似的规则。
```py
numba.cuda.blockDim
```
线程块的形状,在实例化内核时声明。对于给定内核中的所有线程,该值是相同的,即使它们属于不同的块(即每个块都是“满”)。
```py
numba.cuda.blockIdx
```
线程网格中的块索引启动了一个内核。对于 1D 网格,索引(由`x`属性给出)是一个整数,范围从 0 到包括 [`numba.cuda.gridDim`](../cuda-reference/kernel.html#numba.cuda.gridDim "numba.cuda.gridDim") 不包括。当使用多个维度时,每个维度都存在类似的规则。
```py
numba.cuda.gridDim
```
块网格的形状,即由内核调用启动的块的总数,在实例化内核时声明。
### 3.2.4.1。绝对位置
简单的算法倾向于始终以与上面示例中所示相同的方式使用线程索引。 Numba 提供额外的设施来自动进行这样的计算:
```py
numba.cuda.grid(ndim)
```
返回整个块网格中当前线程的绝对位置。 _ndim_ 应该对应于实例化内核时声明的维数。如果 _ndim_ 为 1,则返回单个整数。如果 _ndim_ 为 2 或 3,则返回给定数量的整数的元组。
```py
numba.cuda.gridsize(ndim)
```
返回整个块网格的线程中的绝对大小(或形状)。 _ndim_ 具有与上述 [`grid()`](../cuda-reference/kernel.html#numba.cuda.grid "numba.cuda.grid") 相同的含义。
使用这些函数,增量示例可以变为:
```py
@cuda.jit
def increment_by_one(an_array):
pos = cuda.grid(1)
if pos < an_array.size:
an_array[pos] += 1
```
2D 阵列和线程网格的相同示例是:
```py
@cuda.jit
def increment_a_2D_array(an_array):
x, y = cuda.grid(2)
if x < an_array.shape[0] and y < an_array.shape[1]:
an_array[x, y] += 1
```
请注意,实例化内核时的网格计算仍必须手动完成,例如:
```py
from __future__ import division # for Python 2
threadsperblock = (16, 16)
blockspergrid_x = math.ceil(an_array.shape[0] / threadsperblock[0])
blockspergrid_y = math.ceil(an_array.shape[1] / threadsperblock[1])
blockspergrid = (blockspergrid_x, blockspergrid_y)
increment_a_2D_array[blockspergrid, threadsperblock](an_array)
```
### 3.2.4.2。进一步阅读
有关 CUDA 编程的详细讨论,请参见 [CUDA C 编程指南](http://docs.nvidia.com/cuda/cuda-c-programming-guide)
\ No newline at end of file
此差异已折叠。
# 3.4。编写设备功能
> 原文: [http://numba.pydata.org/numba-doc/latest/cuda/device-functions.html](http://numba.pydata.org/numba-doc/latest/cuda/device-functions.html)
CUDA 设备功能只能从设备内部调用(通过内核或其他设备功能)。要定义设备功能:
```py
from numba import cuda
@cuda.jit(device=True)
def a_device_function(a, b):
return a + b
```
与内核函数不同,设备函数可以返回与普通函数类似的值。
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# 3.11。使用 CUDA 模拟器 调试 CUDA Python
> 原文: [http://numba.pydata.org/numba-doc/latest/cuda/simulator.html](http://numba.pydata.org/numba-doc/latest/cuda/simulator.html)
Numba 包含一个 CUDA Simulator,它使用 Python 解释器和一些额外的 Python 代码实现 CUDA Python 中的大部分语义。这可以用于调试 CUDA Python 代码,方法是在代码中添加 print 语句,或者使用调试器逐步执行单个线程。
内核的执行由模拟器一次一个块执行。为块中的每个线程生成一个线程,并且将这些线程的执行调度留给操作系统。
## 3.11.1。使用模拟器
通过将环境变量 [`NUMBA_ENABLE_CUDASIM`](../reference/envvars.html#envvar-NUMBA_ENABLE_CUDASIM) 设置为 1 来启用模拟器。然后可以正常执行 CUDA Python 代码。在内核中使用调试器的最简单方法是仅停止单个线程,否则难以处理与调试器的交互。例如,下面的内核将在线程`&lt;&lt;&lt;(3,0,0), (1, 0, 0)&gt;&gt;&gt;`中停止:
```py
@cuda.jit
def vec_add(A, B, out):
x = cuda.threadIdx.x
bx = cuda.blockIdx.x
bdx = cuda.blockDim.x
if x == 1 and bx == 3:
from pdb import set_trace; set_trace()
i = bx * bdx + x
out[i] = A[i] + B[i]
```
当使用一维网格和一维块调用时。
## 3.11.2。支持的功能
该模拟器旨在尽可能在真实 GPU 上提供完整的执行模拟 - 特别是,支持以下内容:
* 原子操作
* 恒定记忆
* 本地记忆
* 共享内存:共享内存数组的声明必须位于不同的源代码行上,因为模拟器使用源代码行信息来跟踪跨线程的共享内存分配。
* 支持 [`syncthreads()`](../cuda-reference/kernel.html#numba.cuda.syncthreads "numba.cuda.syncthreads") - 但是,在发散线程进入不同的 [`syncthreads()`](../cuda-reference/kernel.html#numba.cuda.syncthreads "numba.cuda.syncthreads") 调用的情况下,启动不会失败,但会发生意外行为。未来版本的模拟器可以检测到这种情况。
* 支持流 API,但与实际设备不同,所有操作都按顺序和同步进行。因此,在流上进行同步是一种无操作。
* 还支持事件 API,但不提供有意义的计时信息。
* 与 GPU 之间的数据传输 - 特别是使用 [`device_array()`](../cuda-reference/memory.html#numba.cuda.device_array "numba.cuda.device_array")[`device_array_like()`](../cuda-reference/memory.html#numba.cuda.device_array_like "numba.cuda.device_array_like") 创建数组对象。固定存储器 [`pinned()`](../cuda-reference/memory.html#numba.cuda.pinned "numba.cuda.pinned")[`pinned_array()`](../cuda-reference/memory.html#numba.cuda.pinned_array "numba.cuda.pinned_array") 的 API 也受支持,但不会发生钉扎。
* 支持 GPU 上下文列表(`cuda.gpus``cuda.cudadrv.devices.gpus`)的驱动程序 API 实现,并报告单个 GPU 上下文。这个上下文可以像真正的那样关闭和重置。
* 支持 [`detect()`](../cuda-reference/host.html#numba.cuda.detect "numba.cuda.detect") 功能,并报告一个名为 &lt;cite&gt;SIMULATOR&lt;/cite&gt; 的设备。
模拟器的一些限制包括:
* 它不执行类型检查/类型推断。如果 jitted 函数的任何参数类型不正确,或者任何局部变量类型的规范不正确,模拟器将无法检测到。
* 仅模拟一个 GPU。
* 不支持对单个 GPU 的多线程访问,这将导致意外行为。
* 大多数驱动程序 API 未实现。
* 无法将 PTX 代码与 CUDA Python 函数链接。
* Warp 和 warp 级操作尚未实现。
显然,模拟器的速度也远低于真实设备的速度。可能需要减小输入数据的大小和 CUDA 网格的大小,以便使模拟器易于调试。
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# 4. CUDA Python 参考
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
# 5. 用于 AMD ROC GPU 的 Numba
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
# 7. 开发者手册
\ No newline at end of file
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册