Numba 0.44 中文文档(三)

原文:Numba documentation

协议:CC BY-NC-SA 4.0

2.3 提前编译

原文: numba.pydata.org/numba-doc/latest/reference/aot-compilation.html

class numba.pycc.CC(extension_name, source_module=None)

用于从 Numba 编译的 Python 函数生成编译扩展的对象。 extension_name是要生成的扩展名。source_module 是包含这些函数的 Python 模块;如果None,则通过检查调用堆栈来推断。

CC 实例具有以下属性和方法:

name

(只读属性)要生成的扩展模块的名称。

output_dir

(读写属性)扩展模块将写入的目录。默认情况下,它是 source_module 所在的目录。

output_file

(读写属性)扩展模块将写入的文件的名称。默认情况下,这遵循当前平台的 Python 命名约定。

target_cpu

(读写属性)为其生成代码的 CPU 模型的名称。这将选择适当的指令集扩展。默认情况下,选择通用 CPU 以生成可移植代码。

此属性的已识别名称取决于当前体系结构和 LLVM 版本。如果安装了 LLVM,llc -mcpu=help将为您提供一个列表。 x86-64 的例子是"ivybridge""haswell""skylake""broadwell"。您还可以给出值"host",它将选择当前的主机 CPU。

verbose

(读写属性)如果为 true,则在编译扩展时打印输出信息。默认为 False。

@export(exported_name, sig)

使用签名 sig标记要编译的修饰函数。编译的函数将在生成的扩展模块中作为exported_name 公开。

给定 CC 实例中的所有导出名称必须是不同的,否则会引发异常。

compile()

编译所有导出的函数并生成 output_diroutput_file 指定的扩展模块。

distutils_extension(**kwargs)

返回 distutils.core.Extension 实例,允许在传统的setup.py驱动的构建过程中集成扩展模块的生成。可选的 kwargs 允许您将可选参数传递给 Extension 构造函数。

在这种操作模式下,没有必要自己调用 compile() 。此外, output_diroutput_file 将被忽略。

2.4 公用事业

原文: numba.pydata.org/numba-doc/latest/reference/utils.html

2.4.1 处理指针

这些函数可以从纯 Python 以及 nopython 模式中调用。

numba.carray(ptr, shape, dtype=None)

以[C]顺序返回具有给定 形状ptr指向的数据的 Numpy 数组视图。如果给出dtype,则将其用作数组的 dtype,否则从ptr 的类型推断出数组的 dtype。由于返回的数组是视图而不是副本,因此写入它将修改原始数据。

ptr 应该是一个 ctypes 指针对象(使用 POINTER()c_void_p 创建的类型指针)。

shape 应该是整数或整数元组。

dtype 应该是 Numpy dtype 或标量类(即np.dtype('int8')np.int8都被接受)。

numba.farray(ptr, shape, dtype=None)

carray() 相同,但假设数据以 Fortran 顺序排列,并相应地构造数组视图。

2.5 环境变量

原文: numba.pydata.org/numba-doc/latest/reference/envvars.html

Numba 允许通过使用环境变量来改变其行为。除非另有说明,否则这些变量具有整数值且默认为零。

为方便起见,Numba 还支持使用配置文件来保留配置设置。注意:要使用此功能,必须安装pyyaml

配置文件必须命名为.numba_config.yaml并存在于调用 Python 解释器的目录中。在搜索环境变量之前,将读取配置文件(如果存在)以进行配置设置。这意味着环境变量设置将覆盖从配置文件获取的设置(配置文件用于设置永久首选项,而环境变量用于短暂首选项)。

配置文件的格式是YAML格式的字典,它将下面的环境变量(没有NUMBA_前缀)映射到所需的值。例如,要永久打开开发人员模式(NUMBA_DEVELOPER_MODE环境变量)并控制流程图打印(NUMBA_DUMP_CFG环境变量),请创建一个包含以下内容的配置文件:

developer_mode: 1
dump_cfg: 1

在想要使用基于终端背景颜色的设定颜色方案的情况下,这尤其有用。例如,如果终端背景颜色为黑色,则dark_bg颜色方案将非常适合,并且可以通过添加以下内容设置为永久使用:

color_scheme: dark_bg

2.5.1 错误和警告显示

NUMBA_WARNINGS

如果设置为非零,则启用 Numba 警告的打印输出,否则将禁止警告。警告可以深入了解编译过程。

2.5.2 调试

这些变量会影响 JIT 函数编译过程中打印的内容。

NUMBA_DEVELOPER_MODE

如果设置为非零,则开发人员模式会生成完整的回溯并禁用帮助说明。默认值为零。

NUMBA_FULL_TRACEBACKS

如果设置为非零,则在发生异常时启用完全回溯。默认为 <cite>NUMBA_DEVELOPER_MODE</cite> 设置的值。

NUMBA_SHOW_HELP

如果未设置或设置为零,则显示用户级帮助信息。默认为 <cite>NUMBA_DEVELOPER_MODE</cite> 设置的值的否定。

NUMBA_DISABLE_ERROR_MESSAGE_HIGHLIGHTING

如果设置为非零错误消息突出显示被禁用。这对于在 CI 系统上运行测试套件非常有用。

NUMBA_COLOR_SCHEME

更改错误报告中使用的颜色方案(需要安装colorama包才能工作)。有效值为:

  • no_color没有添加颜色,只是粗体字体加权。
  • dark_bg适用于背景较暗的终端。
  • light_bg适用于背景较浅的终端。
  • blue_bg适用于蓝色背景的终端。
  • jupyter_nb适用于 Jupyter 笔记本电脑。

_ 默认值:_ no_color。值的类型是string

NUMBA_DEBUG

如果设置为非零,则在函数编译期间打印出所有可能的调试信息。使用下面的其他变量可以获得更细粒度的控制。

NUMBA_DEBUG_FRONTEND

如果设置为非零,则在编译器前端的操作期间打印出调试信息,直到并包括 Numba 中间表示的生成。

NUMBA_DEBUGINFO

如果设置为非零,则通过设置jitdebug选项的默认值,为整个应用程序启用调试。请注意,启用调试信息会显着增加每个已编译函数的内存消耗。默认值等于 <cite>NUMBA_ENABLE_PROFILING</cite> 的值。

NUMBA_GDB_BINARY

设置gdb二进制文件以用于 Numba 的gdb支持,它采用路径和二进制文件的全名,例如:/path/from/root/to/binary/name_of_gdb_binary这是为了允许使用来自非 COD3 的gdb具有非默认名称的默认位置。如果未设置,则假定gdb位于/usr/bin/gdb

NUMBA_DEBUG_TYPEINFER

如果设置为非零,则打印出有关类型推断的调试信息。

NUMBA_DEBUG_CACHE

如果设置为非零,则打印出有关 JIT 编译缓存操作的信息。

NUMBA_ENABLE_PROFILING

启用 LLVM 的 JIT 事件以支持 jitted 函数的分析。某些分析器下会自动启用此选项。

NUMBA_TRACE

如果设置为非零,则跟踪某些函数调用(函数入口和出口事件,包括参数和返回值)。

NUMBA_DUMP_BYTECODE

如果设置为非零,则打印出已编译函数的 Python 字节码。

NUMBA_DUMP_CFG

如果设置为非零,则打印出有关已编译函数的控制流图的信息。

NUMBA_DUMP_IR

如果设置为非零,则打印出已编译函数的 Numba Intermediate Representation。

NUMBA_DUMP_ANNOTATION

如果设置为非零,则打印出已编译函数的类型注释。

NUMBA_DUMP_LLVM

转储未经优化的 LLVM 汇编程序编译函数源。未经优化的代码通常非常冗长;因此,建议改用 NUMBA_DUMP_OPTIMIZED

NUMBA_DUMP_FUNC_OPT

在 LLVM“函数优化”通过之后但在“模块优化”通过之前转储 LLVM 汇编程序源。这在开发 Numba 本身时很有用,否则使用 NUMBA_DUMP_OPTIMIZED

NUMBA_DUMP_OPTIMIZED

在所有优化过程之后转储已编译函数的 LLVM 汇编器源。输出包括 raw 函数以及与 CPython 兼容的包装器(其名称以wrapper.开头)。请注意,该函数通常也会在包装器内部内联。

NUMBA_DEBUG_ARRAY_OPT

转储与parallel=True jit 装饰器选项相关的处理相关的调试信息。

NUMBA_DEBUG_ARRAY_OPT_RUNTIME

转储与parallel=True jit 装饰器选项关联的运行时调度程序相关的调试信息。

NUMBA_DEBUG_ARRAY_OPT_STATS

转储有关将多少个运算符/调用转换为并行 for 循环以及多少融合在一起的统计信息,这些都与parallel=True jit 装饰器选项相关联。

NUMBA_PARALLEL_DIAGNOSTICS

如果设置为 1 到 4(包括 1 和 4)之间的整数值,Numba 进行的并行变换的诊断信息将写入 STDOUT。值越高,产生的信息越详细。

NUMBA_DUMP_ASSEMBLY

转储已编译函数的本机汇编代码。

也可以看看

故障排除和提示和 Numba 架构。

2.5.3 编译选项

NUMBA_OPT

优化水平;此选项直接传递给 LLVM。

_ 默认值:_ 3

NUMBA_LOOP_VECTORIZE

如果设置为非零,则启用 LLVM 循环向量化。

_ 默认值:_ 1(32 位 Windows 除外)

NUMBA_ENABLE_AVX

如果设置为非零,则在 LLVM 中启用 AVX 优化。默认情况下,Sandy Bridge 和 Ivy Bridge 架构禁用此功能,因为它有时会导致这些平台上的代码速度变慢。

NUMBA_DISABLE_INTEL_SVML

如果设置为非零且 Intel SVML 可用,则将禁用 SVML。

NUMBA_COMPATIBILITY_MODE

如果设置为非零,则 JIT 函数的编译永远不会完全失败,而是生成一个简单地解释函数的回退。只有在从旧的 Numba 版本(0.12 之前)迁移大型代码库时才能使用它,并希望避免一次性破坏所有内容。否则,请不要使用它。

NUMBA_DISABLE_JIT

完全禁用 JIT 编译。 jit() 装饰器就像它不执行任何操作一样,并且装饰函数的调用调用原始 Python 函数而不是编译版本。如果要在代码上运行 Python 调试器,这可能很有用。

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命令行工具,例如:

llc -march=x86 -mattr=help

小费

要强制所有缓存函数(@jit(cache=True))发出可移植代码(在同一架构和操作系统中可移植),只需设置NUMBA_CPU_NAME=generic即可。

NUMBA_FUNCTION_CACHE_SIZE

覆盖函数高速缓存的大小,以便在内存中保留最近反序列化的函数。在像 Dask 这样的系统中,通常会对函数进行多次反序列化。只要解释器​​中有某个引用,Numba 就会缓存函数。此高速缓存大小变量控制将保留不再引用的函数的数量,以防它们将来出现。这种实现并不是真正的 LRU,但是对于大多数情况来说,大尺寸的缓存应该足够了。

_ 默认值:_ 128

2.5.4 GPU 支持

NUMBA_DISABLE_CUDA

如果设置为非零,则禁用 CUDA 支持。

NUMBA_FORCE_CUDA_CC

如果设置,则强制 CUDA 计算功能为给定版本(类型为major.minor的字符串),而不考虑连接的设备。

NUMBA_ENABLE_CUDASIM

如果设置,请不要编译和执行 GPU 的代码,而是使用 CUDA Simulator。用于调试目的。

2.5.5 线程控制

NUMBA_NUM_THREADS

如果设置,则并行 CPU 目标的线程池中的线程数将采用此值。必须大于零。该值与OMP_NUM_THREADSMKL_NUM_THREADS无关。

_ 默认值:_ 运行时确定的系统 CPU 核心数,可通过numba.config.NUMBA_DEFAULT_NUM_THREADS访问。

NUMBA_THREADING_LAYER

此环境变量控制用于 CPU 并行目标(@vectorize(target='parallel')@guvectorize(target='parallel')@njit(parallel=True))的并发执行的库。变量类型是字符串,默认情况下是default,它将根据运行时中可用的内容选择线程层。有效值为(有关这些的更多信息,请参见线程层文档):

  • default - 根据当前运行时可用的内容选择线程层。
  • safe - 选择一个既安全又安全的线程层(需要 TBB 包)。
  • forksafe - 选择叉安全的线程层。
  • threadsafe - 选择线程安全的线程层。
  • tbb - 由英特尔 TBB 支持的线程层。
  • omp - 由 OpenMP 支持的线程层。
  • workqueue - 一个简单的内置工作共享任务调度程序。

2.6 支持的 Python 功能

原文: numba.pydata.org/numba-doc/latest/reference/pysupported.html

除了下面的语言部分,它适用于对象模式和 nopython 模式,此页面仅列出 nopython 模式支持的功能]。

警告

在某些情况下,Numba 行为与 Python 语义不同。我们强烈建议审查与 Python 语义的偏差,以熟悉这些差异。

2.6.1 语言

2.6.1.1 构造

Numba 努力支持尽可能多的 Python 语言,但 Numba 编译的函数中没有一些语言功能。目前不支持以下 Python 语言功能:

  • 类定义
  • 异常处理(try .. excepttry .. finally
  • 上下文管理(with语句)
  • 一些理解(支持列表理解,但不支持字典,集合或生成器理解)
  • 发电机代表团(yield from

raise语句以多种形式支持:

  • raise(重新提高当前例外)
  • raise SomeException
  • raise SomeException(&lt;arguments&gt;):在 nopython 模式中,构造函数参数必须是编译时常量

同样,支持assert语句,有或没有错误消息。

2.6.1.2 功能

2.6.1.2.1。函数调用

Numba 支持使用位置和命名参数的函数调用,以及具有默认值和*args的参数(注意*args的参数只能是元组,而不是列表)。不支持显式**kwargs

只要可以完全内联函数,就支持对本地定义的内部函数的函数调用。

2.6.1.2.2。作为参数的函数

函数可以作为参数传递给另一个函数。但是,他们无法归还。例如:

from numba import jit

@jit
def add1(x):
    return x + 1

@jit
def bar(fn, x):
    return fn(x)

@jit
def foo(x):
    return bar(add1, x)

# Passing add1 within numba compiled code.
print(foo(1))
# Passing add1 into bar from interpreted code
print(bar(add1, 1))

注意

Numba 不将函数对象作为真实对象处理。将函数分配给变量后,无法将变量重新分配给其他函数。

2.6.1.2.3。内部功能和闭合

Numba 现在支持内部函数,只要它们是非递归的并且只在本地调用,但不作为参数传递或作为结果返回。还支持在内部函数内使用闭包变量(在外部作用域中定义的变量)。

2.6.1.2.4。递归调用

支持大多数递归调用模式。唯一的限制是递归被调用者必须有一个返回的控制流路径而不会递归。 Numba 能够在不指定函数类型签名的情况下对类型推断递归函数(这在 numba 0.28 及更早版本中是必需的)。递归调用甚至可以调用函数的不同重载。

2.6.1.3 发电机

Numba 支持生成器功能,并且能够在对象模式和 nopython 模式中编译它们。返回的生成器既可以使用 Numba 编译的代码,也可以使用常规的 Python 代码。

不支持发生器的协同特征(即 generator.send()generator.throw()generator.close() 方法)。

2.6.2 内置类型

2.6.2.1 int,bool

支持算术运算和真值。

支持以下属性和方法:

  • .conjugate()
  • .real
  • .imag

2.6.2.2 浮动,复杂

支持算术运算和真值。

支持以下属性和方法:

  • .conjugate()
  • .real
  • .imag

2.6.2.3 str

Numba 在 Python 3 中支持(Unicode)字符串。字符串可以作为参数传递到 nopython 模式,以及从 nopython 模式构造和返回。与 Python 一样,切片(即使长度为 1)也会返回一个新的引用计数字符串。将来可能会引入有效访问单个字符的优化代码路径。

内存中的表示与 Python 3.4 中引入的相同,每个字符串都有一个标记,用于指示字符串是否在内存中使用 1,2 或 4 字节字符宽度。当组合不同编码的字符串时(如串联),结果字符串自动使用两个输入字符串的较大字符宽度。字符串切片也使用与原始字符串相同的字符宽度,即使切片可以用较窄的字符宽度表示。 (当然,这些细节对用户是不可见的。)

目前支持以下函数,属性和方法:

  • len()
  • +(字符串串联)
  • in.contains()
  • ==&lt;&lt;=&gt;&gt;=(比较)
  • .startswith()
  • .endswith()
  • .find()
  • .split()
  • .join()

在未来的 Numba 版本中将添加其他操作以及对 Python 2 字符串/ Python 3 字节的支持。可能永远不会支持 Python 2 Unicode 对象。

警告

已知某些操作的性能比 CPython 实现慢。这些包括子串搜索(in.contains()find())和字符串创建(如.split())。提高字符串性能是一项持续的任务,但 CPython 的速度不可能单独超越基本的字符串操作。 Numba 最成功地用于碰巧涉及字符串的较大算法,其中基本字符串操作不是瓶颈。

2.6.2.4 元组

支持以下操作:

  • 元组结构
  • 元组拆包
  • 元组之间的比较
  • 对同类元组进行迭代和索引
  • 元组之间的加法(连接)
  • 用常量切片切片元组
  • 元组的索引方法

2.6.2.5 清单

支持从 JIT 编译的函数创建和返回列表,以及所有方法和操作。列表必须严格同质:Numba 将拒绝任何包含不同类型对象的列表,即使类型是兼容的(例如,[1, 2.5]被拒绝,因为它包含 intfloat )。

例如,要创建数组列表:

In [1]: from numba import njit

In [2]: import numpy as np

In [3]: @njit
  ...: def foo(x):
  ...:     lst = []
  ...:     for i in range(x):
  ...:         lst.append(np.arange(i))
  ...:     return lst
  ...:

In [4]: foo(4)
Out[4]: [array([], dtype=int64), array([0]), array([0, 1]), array([0, 1, 2])]

2.6.2.5.1。列表反射

在 nopython 模式下,Numba 不对 Python 对象进行操作。 list被编译成内部表示。任何list参数必须在进入 nopython 模式的过程中转换为此表示形式,并且必须通过称为 reflection 的进程在原始 Python 对象中恢复其包含的元素。需要反射来维护与常规 Python 代码中相同的语义。但是,对于大型列表,反射过程可能很昂贵,而对于包含反射数据类型的列表则不支持。由于此限制,用户无法使用 list-of-list 作为参数。

注意

将列表传递给 JIT 编译的函数时,在函数返回之前,对 Python 解释器不会显示对列表所做的任何修改。 (反射过程的局限性。)

警告

列表排序当前使用快速排序算法,该算法具有与 Python 使用的算法不同的性能特征。

2.6.2.5.2。列表理解

Numba 支持列表理解。例如:

In [1]: from numba import njit

In [2]: @njit
  ...: def foo(x):
  ...:     return [[i for i in range(n)] for n in range(x)]
  ...:

In [3]: foo(3)
Out[3]: [[], [0], [0, 1]]

注意

在版本 0.39.0 之前,Numba 不支持创建嵌套列表。

Numba 还支持“数组理解”,这是一个列表理解,紧接着是对 numpy.array() 的调用。以下是生成 2D Numpy 数组的示例:

from numba import jit
import numpy as np

@jit(nopython=True)
def f(n):
  return np.array([ [ x * y for x in range(n) ] for y in range(n) ])

在这种情况下,Numba 能够优化程序以直接分配和初始化结果数组,而无需分配中间列表对象。因此,这里列表推导的嵌套不是问题,因为这里创建了多维数组而不是嵌套列表。

此外,当与 CPU 上的并行选项结合使用时,Numba 支持并行阵列压缩。

2.6.2.6 设置

JIT 编译的函数支持集合上的所有方法和操作。

集必须是严格同质的:Numba 将拒绝包含不同类型对象的任何集合,即使类型是兼容的(例如,{1, 2.5}被拒绝,因为它包含 intfloat )。

注意

将一个集合传递给 JIT 编译的函数时,在该函数返回之前,对该集合所做的任何修改都不会对 Python 解释器可见。

2.6.2.7 字典

警告

numba.typed.Dict是一项实验性功能。 API 可能会在将来的版本中发生变化。

Numba 不直接支持 Python dict,因为它是一个无类型的容器,可以将任何 Python 类型作为成员。为了生成有效的机器代码,Numba 需要密钥和字典的值具有预先声明的固定类型。为了实现这一点,Numba 有一个类型字典numba.typed.Dict,用户必须使用Dict.empty()构造函数方法显式声明 key-type 和 value-type。这个类型化的字典与 Python dict具有相同的 API,它实现了collections.MutableMapping接口,可用于解释的 Python 代码和 JIT 编译的 Numba 函数。因为键入的字典在 Numba 的本机,未装箱的数据布局中存储键和值,所以将 Numba 字典传递到 nopython 模式的开销非常低。但是,这意味着使用 Python 解释器中的类型字典比常规字典慢,因为 Numba 在获取或设置项目时必须对 key 和 unbox 进行包装和取消设置。

与 Python 的dict相比,类型字典的一个重要区别是当存储键或值时会发生隐式转换。因此,如果类型转换失败, setitem 操作可能会失败。

注意

numba.typed.Dict尚未使用Dict()构造,必须使用Dict.empty(key_type, value_type)类方法来构造类型化字典。

应该注意,Numba 类型字典是使用与 CPython 3.7 字典相同的算法实现的。因此,键入的字典是有序的,并且具有与 CPython 实现相同的冲突解决方案。

除了上面关于类型规范之外,对于可以用作键入字典中的键和/或值的类型存在限制,最值得注意的是当前不支持 Numba SetList类型。可接受的键/值类型包括但不限于:unicode 字符串,数组,标量,元组。随着 Numba 不断改进,预计这些限制将会放松。

这是从解释代码创建numba.typed.Dict实例并在 jit 代码中使用字典的示例:

from ex_typed_dict_from_cpython of examples/dict_usage.py

|

 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

|

import numpy as np
from numba import njit
from numba import types
from numba.typed import Dict

# The Dict.empty() constructs a typed dictionary.
# The key and value typed must be explicitly declared.
d = Dict.empty(
    key_type=types.unicode_type,
    value_type=types.float64[:],
)

# The typed-dict can be used from the interpreter.
d['posx'] = np.asarray([1, 0.5, 2], dtype='f8')
d['posy'] = np.asarray([1.5, 3.5, 2], dtype='f8')
d['velx'] = np.asarray([0.5, 0, 0.7], dtype='f8')
d['vely'] = np.asarray([0.2, -0.2, 0.1], dtype='f8')

# Here's a function that expects a typed-dict as the argument
@njit
def move(d):
    # inplace operations on the arrays
    d['posx'] += d['velx']
    d['posy'] += d['vely']

print('posx: ', d['posx'])  # Out: posx:  [1\.  0.5 2\. ]
print('posy: ', d['posy'])  # Out: posy:  [1.5 3.5 2\. ]

# Call move(d) to inplace update the arrays in the typed-dict.
move(d)

print('posx: ', d['posx'])  # Out: posx:  [1.5 0.5 2.7]
print('posy: ', d['posy'])  # Out: posy:  [1.7 3.3 2.1]

|

这是一个从 jit 代码创建numba.typed.Dict实例并在解释代码中使用字典的示例:

from ex_typed_dict_njit of examples/dict_usage.py

|

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

|

import numpy as np
from numba import njit
from numba import types
from numba.typed import Dict

# Make array type.  Type-expression is not supported in jit functions.
float_array = types.float64[:]

@njit
def foo():
    # Make dictionary
    d = Dict.empty(
        key_type=types.unicode_type,
        value_type=float_array,
    )
    # Fill the dictionary
    d["posx"] = np.arange(3).astype(np.float64)
    d["posy"] = np.arange(3, 6).astype(np.float64)
    return d

d = foo()
# Print the dictionary
print(d)  # Out: {posx: [0\. 1\. 2.], posy: [3\. 4\. 5.]}

|

2.6.2.8 无

身份测试支持 None 值(使用 optional 类型时)。

2.6.2.9 bytes,bytearray,memoryview

bytearray 类型,在 Python 3 上, bytes 类型支持索引,迭代和检索 len()。

memoryview 类型支持索引,切片,迭代,检索 len()以及以下属性:

2.6.3 内置功能

支持以下内置函数:

  • abs()
  • bool
  • complex
  • divmod()
  • enumerate()
  • float
  • hash() (参见下面的 Hashing )
  • int :只有单参数形式
  • iter() :只有单参数形式
  • len()
  • min()
  • max()
  • next() :只有单参数形式
  • print() :仅限数字和字符串;没有filesep参数
  • range :即使在 Python 2 中,语义也类似于 Python 3:返回范围对象而不是值数组。范围的唯一允许使用是作为可调用函数(不能将范围作为参数传递给 jitted 函数或从 jitted 函数返回范围)。
  • round()
  • sorted() :不支持key参数
  • type():只有单参数形式,并且只在某些类型上(例如数字和命名元组)
  • zip()

2.6.3.1 哈希

支持 hash() 内置并为所有支持的可哈希类型生成哈希值,具有以下特定于 Python 版本的行为:

在 Python 3 下,Numba 计算的哈希值将与sys.hash_info.algorithmsiphash24(默认值)的条件下 CPython 中计算的哈希值完全匹配。

在 Python 2 下,由 Numba 计算的哈希值将遵循为 Python 3 描述的行为,sys.hash_info.algorithm被模拟为siphash24。没有尝试复制 Python 2 散列行为。

PYTHONHASHSEED环境变量以与 CPython 文档中描述的方式完全相同的方式影响散列行为。

2.6.4 标准库模块

2.6.4.1 array

通过缓冲协议提供对 array.array 类型的有限支持。支持索引,迭代和获取 len()。除"u"外,支持所有类型代码。

2.6.4.2 cmath

支持 cmath 模块的以下功能:

2.6.4.3 collections

collections.namedtuple() 返回的命名元组类的支持方式与支持常规元组的方式相同。还支持构造函数中的属性访问和命名参数。

在 Numba 代码中创建一个命名的元组类是 而不是 支持;必须在全局级别创建该类。

2.6.4.4 ctypes

Numba 能够使用以下参数和返回类型调用 ctypes 声明的函数:

2.6.4.5 enum

支持 enum.Enumenum.IntEnum 子类。

2.6.4.6 math

支持 math 模块的以下功能:

2.6.4.7 operator

支持 operator 模块的以下功能:

2.6.4.8 functools

支持 functools.reduce() 功能,但需要<cite>初始值设定项</cite>参数。

2.6.4.9 random

Numba 支持 random 模块的顶级功能,但不允许您创建单独的 Random 实例。使用 Mersenne-Twister 发电机,具有专用的内部状态。它在启动时初始化,并从操作系统中提取熵。

注意

从非 Numba 代码(或从对象模式代码)调用 random.seed() 将播种 Python 随机生成器,而不是 Numba 随机生成器。

注意

从版本 0.28.0 开始,发生器是线程安全的和叉安全的。每个线程和每个进程将产生独立的随机数流。

也可以看看

Numba 还支持来自 Numpy 随机模块的大多数其他发行版。

2.6.4.10 heapq

支持 heapq 模块的以下功能:

注意:必须为堆添加至少一个值以允许其类型被推断;假设堆项目在类型上是同类的。

2.6.5 第三方模块

2.6.5.1 cffi

与 ctypes 类似,Numba 能够使用以下 C 类型和任何派生指针类型调用 cffi - 声明的外部函数:

  • char
  • short
  • int
  • long
  • long long
  • unsigned char
  • unsigned short
  • unsigned int
  • unsigned long
  • unsigned long long
  • int8_t
  • uint8_t
  • int16_t
  • uint16_t
  • int32_t
  • uint32_t
  • int64_t
  • uint64_t
  • float
  • double
  • ssize_t
  • size_t
  • void

cffi.FFICompiledFFI对象的from_buffer()方法支持传递 Numpy 数组和其他类似缓冲区的对象。只接受 连续 参数。 from_buffer()的参数被转换为适当 C 类型的原始指针(例如float64数组的double *)。

可以向 Numba 注册用于从缓冲区到适当的 C 类型的转换的附加类型映射。这可能包括结构类型,但它只允许调用接受结构指针的函数 - 不支持按值传递结构。要注册映射,请使用:

numba.cffi_support.register_type(cffi_type, numba_type)

在使用 Numba 编译的函数中的任何函数之前,必须在 Numba 中注册外部 cffi 模块:

numba.cffi_support.register_module(mod)

使用 Numba 注册 cffi 外线模块mod

内联 cffi 模块不需要注册。

2.7 支持的 NumPy 功能

原文: numba.pydata.org/numba-doc/latest/reference/numpysupported.html

注意

支持绝大多数 NumPy 1.16 行为,但涉及NaTdatetimetimedelta使用与早期版本中存在的行为相匹配。 ufunc 套件尚未扩展以适应 NumPy 1.16 中存在的两个新的时间计算相关的附加功能。此外,在某些输入模式中出现NaN时,ediff1dinterp函数在复制输出方面存在一些小问题。

Numba 的一个目标是与 NumPy 无缝集成。 NumPy 数组为同类数据集提供了一种有效的存储方法。 NumPy dtypes 在编译时提供有用的类型信息,并且内存中潜在大量数据的常规结构化存储为代码生成提供了理想的内存布局。 Numba 擅长生成在 NumPy 数组之上执行的代码。

NumbP 在 Numba 的支持有多种形式:

  • Numba 了解对 NumPy ufuncs 的调用,并能够为其中许多人生成等效的本机代码。
  • Numba 直接支持 NumPy 阵列。访问 Numpy 数组非常有效,因为索引会降低到可能时直接访问内存。
  • Numba 能够产生 ufuncsgufuncs 。这意味着可以在 Python 中实现 ufuncs 和 gufunc,使用 NumPy C API 获得与 C 扩展模块中实现的 ufuncs / gufuncs 相当的速度。

除非另有说明,否则以下部分将重点介绍 nopython 模式中支持的 Numpy 功能。

2.7.1 标量类型

Numba 支持以下 Numpy 标量类型:

  • 整数:所有符号的整数,以及最多 64 位的任何宽度
  • 布尔
  • **实数:**单精度(32 位)和双精度(64 位)实数
  • **复数:**单精度(2x32 位)和双精度(2x64 位)复数
  • 日期时间和时间戳:任何单位的
  • 字符序列(但没有可用的操作)
  • **结构化标量:**结构标量由上述任何类型和上述类型的数组组成

不支持以下标量类型和功能:

  • 任意 Python 对象
  • 半精度和扩展精度实数和复数
  • 嵌套结构化标量结构化标量字段可能不包含其他结构化标量

标量 Numpy 数字支持的操作与intfloat等效内置类型相同。您可以使用类型的构造函数从不同的类型或宽度进行转换。

结构化标量支持属性获取和设置,以及使用常量字符串的成员查找。

也可以看看

Numpy scalars 参考。

2.7.2 数组类型

支持上述任何标量类型的 Numpy 数组,无论其形状或布局如何。

2.7.2.1 数组访问

数组支持正常迭代。支持完整的基本索引和切片。还支持高级索引的子集:只允许一个高级索引,它必须是一维数组(它也可以与任意数量的基本索引组合)。

也可以看看

Numpy 索引参考。

2.7.2.2 属性

支持 Numpy 数组的以下属性:

2.7.2.2.1。 flags对象

flags 属性返回的对象支持contiguousc_contiguousf_contiguous属性。

2.7.2.2.2。 flat对象

flat 属性返回的对象支持迭代和索引,但要小心:非 C 连续数组的索引非常慢。

2.7.2.2.3。 realimag属性

无论 dtype 如何,Numpy 都支持这些属性,但 Numba 选择限制其支持以避免潜在的用户错误。对于数字 dtypes,Numba 遵循 Numpy 的行为。 real 属性返回复数数组实部的视图,它表现为其他数字 dtypes 的标识函数。 imag 属性返回复数数组的虚部的视图,并返回具有相同形状的零数组和其他数字 dtypes 的 dtype。对于非数字 dtypes,包括所有结构化/记录 dtypes,使用这些属性将导致编译时( <cite>TypingError</cite> )错误。此行为与 Numpy 不同,但选择此行为是为了避免与重叠这些属性的字段名称混淆。

2.7.2.3 计算

Numpy 数组的以下方法以其基本形式支持(没有任何可选参数):

相应的顶级 Numpy 函数(例如 numpy.prod() )也同样受支持。

2.7.2.4 其他方法

支持以下 Numpy 数组方法:

  • argsort() (值'quicksort''mergesort'支持kind关键字参数)
  • astype() (仅 1 参数形式)
  • copy() (不带参数)
  • dot() (仅 1 参数形式)
  • flatten() (无订单参数;仅’C’订单)
  • item() (不带参数)
  • itemset() (仅 1 参数形式)
  • ravel() (无订单参数;仅’C’订单)
  • reshape() (仅 1 参数形式)
  • sort() (不带参数)
  • sum() (有或没有axis参数)
    • 如果axis参数是编译时常量,则支持所有有效值。超出范围的值将在编译时产生LoweringError
    • 如果axis参数不是编译时常量,则仅支持 0 到 3 之间的值。超出范围的值将导致运行时异常。
  • transpose()
  • view() (仅 1 参数形式)

警告

排序可能比 Numpy 的实现略慢。

2.7.3 功能

2.7.3.1 线性代数

浮点数和复数的 1-D 和 2-D 连续数组支持基本线性代数:

注意

这些功能的实现需要安装 Scipy 0.16+。

2.7.3.2 减少

支持以下缩减功能:

2.7.3.3 其他功能

支持以下顶级功能:

支持以下构造函数,包括数字输入(用于构造标量)或序列(用于构造数组):

  • numpy.bool_
  • numpy.complex64
  • numpy.complex128
  • numpy.float32
  • numpy.float64
  • numpy.int8
  • numpy.int16
  • numpy.int32
  • numpy.int64
  • numpy.intc
  • numpy.intp
  • numpy.uint8
  • numpy.uint16
  • numpy.uint32
  • numpy.uint64
  • numpy.uintc
  • numpy.uintp

支持以下机器参数类,所有纯数字属性:

2.7.3.4 文字阵列

Python 和 Numba 都没有实际的数组文字,但你可以通过在嵌套元组上调用 numpy.array() 来构造任意数组:

a = numpy.array(((a, b, c), (d, e, f)))

(Numba 尚不支持嵌套列表)

2.7.4 模块

2.7.4.1 random

Numba 支持 numpy.random 模块中的顶级函数,但不允许您创建单独的 RandomState 实例。使用与标准随机模块相同的算法(因此适用相同的注释),但具有独立的内部状态:来自一个发电机的播种或抽取数字不会影响另一个。

支持以下功能。

2.7.4.1.1。初始化
2.7.4.1.2。简单随机数据
2.7.4.1.3。排列
2.7.4.1.4。分布

警告

以下函数不支持 <cite>size</cite> 参数。

注意

从非 Numba 代码(或从对象模式代码)调用 numpy.random.seed() 将为 Numpy 随机生成器播种,而不是 Numba 随机生成器。

注意

从版本 0.28.0 开始,发生器是线程安全的和叉安全的。每个线程和每个进程将产生独立的随机数流。

2.7.4.2 stride_tricks

支持numpy.lib.stride_tricks模块的以下功能:

  • as_strided()步长 参数是必需的,不支持 subok 参数)

2.7.5 标准 ufuncs

Numba 的一个目标是让 Numba 理解 NumPy 中的所有标准 ufuncs。当编译函数时找到支持的 ufunc 时,Numba 将 ufunc 映射到等效的本机代码。这允许在 Numba 代码中使用那些在 nopython 模式中编译的 ufunc。

2.7.5.1 限制

现在,只有一些标准的 ufunc 工作在 nopython 模式。以下是 Numba 知道的不同标准 ufunc 的列表,其排序方式与 NumPy 文档中的排序方式相同。

2.7.5.2 数学运算

UFUNC模式
名称对象模式
减去
划分
logaddexp
logaddexp2
true_divide
floor_divide
功率
剩余
MOD
FMOD
ABS
绝对
晶圆厂
RINT
标志
连词
EXP
EXP2
日志
LOG2
LOG10
的 expm1
log1p
开方
广场
倒数
共轭

2.7.5.3 三角函数

UFUNC模式
名称对象模式
COS
黄褐色
反正弦
ARCCOS
反正切
arctan2
hypot 将
双曲正弦
护身用手杖
正切
arcsinh
arccosh
arctanh
deg2rad
rad2deg
弧度

2.7.5.4 比特功能

UFUNC模式
名称对象模式
bitwise_and
bitwise_or
bitwise_xor
bitwise_not
倒置
左移
right_shift

2.7.5.5 比较功能

UFUNC模式
名称对象模式
更大
greater_equal
less_equal
NOT_EQUAL
等于
logical_and
逻辑或
logical_xor
logical_not
最大值
最低限度
FMAX
FMIN

2.7.5.6 浮动功能

UFUNC模式
名称对象模式
ISFINITE
isinf
isnan
signbit
复制符号
函数 nextafter
MODF
ldexp是的(*)
frexp
地板
小区
TRUNC
间距

(*)Windows 32 位不支持

2.8 与 Python 语义的偏差

原文: numba.pydata.org/numba-doc/latest/reference/pysemantics.html

2.8.1 异常和内存分配

由于当前编译器在处理异常时的限制,在引发异常的函数中分配的内存(几乎总是 NumPy 数组)将泄漏。这是一个已修复的已知问题,但与此同时,最好在函数之外进行内存分配,这也可能引发异常。

2.8.2 整数宽度

虽然 Python 具有任意大小的整数,但 Numba 编译函数中的整数通过类型推断(通常是机器整数的大小)获得固定大小。这意味着算术运算可以包围或产生未定义的结果或溢出。

可以通过显式类型规范覆盖类型推断,期望对整数宽度进行细粒度控制。

也可以看看

增强建议 1:整数输入的变化

2.8.3 布尔反转

在 Python boolean 上调用按位补码运算符(~运算符)返回一个整数,而 Numpy 布尔值上的相同运算符返回另一个布尔值:

>>> ~True
-2
>>> ~np.bool_(True)
False

Numba 遵循 Numpy 语义。

2.8.4 全局和闭包变量

在 nopython 模式中,Numba 的全局和闭包变量是 冻结:Numba 编译的函数在编译函数时看到这些变量的值。此外,无法从功能更改其值。

Numba 可能会或可能不会复制已编译函数内引用的全局变量。通过不变性假设复制小的全局数组以进行潜在的编译器优化。但是,不会复制大型全局数组以节省内存。 “小”和“大”的定义可能会改变。

去做

该文件需要完成。

2.9 浮点陷阱

原文: 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 也会强制某些线性代数运算以双精度模式运行。当所有输入都是float32complex64时,Numba 将始终观察输入的精度,并调用单精度线性代数例程。

Numba 中numpy.linalg例程的实现仅支持在提供底层核心功能的 LAPACK 函数中使用的浮点类型。因此,仅支持float32float64complex64complex128类型。如果用户有例如在int32类型中,在用于这些例程之前,必须对浮点类型执行适当的类型转换。这个决定的原因是基本上避免必须复制在 Numpy 中做出的类型转换选择,并且还鼓励用户为他们正在进行的操作选择最佳浮点类型。

2.9.1.3 混合型操作

Numpy 最常返回float64作为使用混合整数和浮点操作数的计算结果(典型示例是幂运算符**)。相比之下,Numba 将在浮点操作数中选择最高精度,因此例如float32 ** int32将返回float32,而不管输入值如何。这使得性能特征更容易预测,但如果需要额外的精度,则应明确地将输入转换为float64

2.9.2 警告和错误

当调用 vectorize() 创建的 ufunc 时,Numpy 将通过检查 FPU 错误字来确定是否发生错误。然后它可能会打印出警告或引发异常(例如RuntimeWarning: divide by zero encountered),具体取决于当前的错误处理设置。

但是,根据 LLVM 如何优化 ufunc 代码,可能会出现一些虚假警告或错误。如果您遇到此问题,我们建议您调用 numpy.seterr() 来更改 Numpy 的错误处理设置,或者 numpy.errstate 上下文管理器暂时切换它们:

with np.errstate(all='ignore'):
    x = my_ufunc(y)

2.10 Python 2.7 寿命终止计划

原文: numba.pydata.org/numba-doc/latest/reference/python27-eol.html

根据 PEP 373 ,Python 2.7 将在 2020 年停止支持,尽管尚未正式选择。像许多项目一样,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 支持的时间表。由于 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 分支。

如果对上述时间表有疑虑,请在我们的问题跟踪器中提出问题

3. 用于 CUDA GPU 的 Numba

3.1 概述

原文: 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 编程指南

3.1.3 要求

3.1.3.1 支持的 GPU

Numba 支持支持 CUDA 的 GPU,其计算能力为 2.0 或更高,具有最新数据的 Nvidia 驱动程序。

3.1.3.2 软件

您将需要安装 CUDA 工具包。如果您使用的是 Conda,只需输入:

$ conda install cudatoolkit

3.1.4 缺少 CUDA 功能

Numba 尚未实现 CUDA 的所有功能。下面列出了一些缺少的功能:

  • 动态并行
  • 纹理记忆

3.2 编写 CUDA 内核

原文: numba.pydata.org/numba-doc/latest/cuda/kernels.html

3.2.1 简介

与用于编程 CPU 的传统顺序模型不同,CUDA 具有执行模型。在 CUDA 中,您编写的代码将由多个线程同时执行(通常为数百或数千)。您的解决方案将通过定义 gridblocksthreads 的线程层次结构来建模。

Numba 的 CUDA 支持公开了用于声明和管理这种线程层次结构的工具。这些设施与 NVidia 的 CUDA C 语言大致相似。

Numba 还暴露了三种 GPU 内存:全局设备内存(连接到 GPU 本身的大型,相对较慢的片外内存),片上共享内存和 []本地记忆](memory.html#cuda-local-memory)。除了最简单的算法外,您必须仔细考虑如何使用和访问内存,以最大限度地减少带宽需求和争用。

3.2.2 内核声明

内核函数 是一个 GPU 函数,用于从 CPU 代码(*)调用。它赋予它两个基本特征:

  • 内核无法显式返回值;所有结果数据必须写入传递给函数的数组(如果计算一个标量,你可能会传递一个单元素数组);
  • 内核在被调用时显式声明它们的线程层次结构:即线程块的数量和每个块的线程数(注意,当内核被编译一次时,可以使用不同的块大小或网格大小多次调用它)。

乍一看,使用 Numba 编写 CUDA 内核看起来非常像为 CPU 编写 JIT 函数:

@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 内核调用

内核通常以以下方式启动:

threadsperblock = 32
blockspergrid = (an_array.size + (threadsperblock - 1)) // threadsperblock
increment_by_oneblockspergrid, threadsperblock

我们在这里注意两个步骤:

  • 通过指定多个块(或“每个网格的块”)以及每个块的多个线程来实例化内核。两者的乘积将给出启动的线程总数。内核实例化是通过编译内核函数(此处为increment_by_one)并使用整数元组对其进行索引来完成的。
  • 运行内核,通过传递输入数组(以及任何必要的单独输出数组)。默认情况下,运行内核是同步的:当内核完成执行并且数据被同步回来时,函数返回。

3.2.3.1 选择块大小

在声明内核所需的线程数时,拥有两级层次结构似乎很奇怪。块大小(即每个块的线程数)通常至关重要:

  • 在软件方面,块大小决定共享共享内存的给定区域的线程数。
  • 在硬件方面,块大小必须足够大才能完全占用执行单元;建议可在 CUDA C 编程指南中找到。

3.2.3.2 多维块和网格

为了帮助处理多维数组,CUDA 允许您指定多维块和网格。在上面的示例中,您可以使blockspergridthreadsperblock元组为一个,两个或三个整数。与等效大小的 1D 声明相比,这不会改变生成代码的效率或行为,但可以帮助您以更自然的方式编写算法。

3.2.4 螺纹定位

运行内核时,每个线程执行一次内核函数的代码。因此,它必须知道它所在的线程,以便知道它负责哪个数组元素(复杂的算法可能定义更复杂的责任,但基本原理是相同的)。

一种方法是让线程定位它在网格和块中的位置,并手动计算在数组中对应的位置:

@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

注意

除非您确定块大小和网格大小是数组大小的除数,否则必须检查边界,如上所示。

threadIdxblockIdxblockDimgridDim 是 CUDA 后端为鞋底提供的特殊对象了解线程层次结构的几何以及当前线程在该几何中的位置的目的。

这些对象可以是 1D,2D 或 3D,具体取决于内核调用的方式。要访问每个维度的值,请分别使用这些对象的xyz属性。

numba.cuda.threadIdx

当前线程块中的线程索引。对于 1D 块,索引(由x属性给出)是一个整数,范围从 0 到包括 numba.cuda.blockDim 不包括。当使用多个维度时,每个维度都存在类似的规则。

numba.cuda.blockDim

线程块的形状,在实例化内核时声明。对于给定内核中的所有线程,该值是相同的,即使它们属于不同的块(即每个块都是“满”)。

numba.cuda.blockIdx

线程网格中的块索引启动了一个内核。对于 1D 网格,索引(由x属性给出)是一个整数,范围从 0 到包括 numba.cuda.gridDim 不包括。当使用多个维度时,每个维度都存在类似的规则。

numba.cuda.gridDim

块网格的形状,即由内核调用启动的块的总数,在实例化内核时声明。

3.2.4.1 绝对位置

简单的算法倾向于始终以与上面示例中所示相同的方式使用线程索引。 Numba 提供额外的设施来自动进行这样的计算:

numba.cuda.grid(ndim)

返回整个块网格中当前线程的绝对位置。 ndim应该对应于实例化内核时声明的维数。如果ndim为 1,则返回单个整数。如果ndim 为 2 或 3,则返回给定数量的整数的元组。

numba.cuda.gridsize(ndim)

返回整个块网格的线程中的绝对大小(或形状)。 ndim 具有与上述 grid() 相同的含义。

使用这些函数,增量示例可以变为:

@cuda.jit
def increment_by_one(an_array):
    pos = cuda.grid(1)
    if pos < an_array.size:
        an_array[pos] += 1

2D 阵列和线程网格的相同示例是:

@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

请注意,实例化内核时的网格计算仍必须手动完成,例如:

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_arrayblockspergrid, threadsperblock

3.2.4.2 进一步阅读

有关 CUDA 编程的详细讨论,请参见 CUDA C 编程指南

3.3 内存管理

原文: numba.pydata.org/numba-doc/latest/cuda/memory.html

3.3.1 数据传输

尽管 Numba 可以自动将 NumPy 阵列传输到设备,但只有在内核完成时始终将设备内存传输回主机,它才能保守。为避免不必要的只读数组传输,您可以使用以下 API 手动控制传输:

numba.cuda.device_array(shape, dtype=np.float, strides=None, order='C', stream=0)

分配一个空设备 ndarray。与numpy.empty()类似。

numba.cuda.device_array_like(ary, stream=0)

使用数组中的信息调用 cuda.devicearray()。

numba.cuda.to_device(obj, stream=0, copy=True, to=None)

将 numpy ndarray 或结构化标量分配并传输到设备。

要将 host-&gt;设备复制为 numpy 数组:

ary = np.arange(10)
d_ary = cuda.to_device(ary)

要将传输排入队列:

stream = cuda.stream()
d_ary = cuda.to_device(ary, stream=stream)

得到的d_aryDeviceNDArray

要复制 device-&gt;主机:

hary = d_ary.copy_to_host()

要将 device-&gt;主机复制到现有数组:

ary = np.empty(shape=d_ary.shape, dtype=d_ary.dtype)
d_ary.copy_to_host(ary)

要将传输排入队列:

hary = d_ary.copy_to_host(stream=stream)

除了设备阵列,Numba 还可以使用任何实现 cuda 阵列接口的对象。通过使用以下 API 创建 GPU 缓冲区视图,还可以将这些对象手动转换为 Numba 设备阵列:

numba.cuda.as_cuda_array(obj)

从任何实现 cuda-array-interface 的对象创建 DeviceNDArray。

创建基础 GPU 缓冲区的视图。没有复制数据。生成的 DeviceNDArray 将从 <cite>obj</cite> 获取引用。

numba.cuda.is_cuda_array(obj)

测试对象是否已定义 <cite>cuda_array_interface</cite> 。

不验证接口的有效性。

3.3.1.1 设备阵列

设备阵列引用具有以下方法。这些方法将在主机代码中调用,而不是在 CUDA-jitted 函数中调用。

class numba.cuda.cudadrv.devicearray.DeviceNDArray(shape, strides, dtype, stream=0, writeback=None, gpu_data=None)

GPU 上阵列类型

copy_to_host(ary=None, stream=0)

如果aryNone,则将self复制到ary或创建新的 Numpy ndarray。

如果给出了 CUDA stream,则传输将作为给定流的一部分异步进行。否则,传输是同步的:复制完成后函数返回。

始终返回主机阵列。

例:

import numpy as np
from numba import cuda

arr = np.arange(1000)
d_arr = cuda.to_device(arr)

my_kernel100, 100

result_array = d_arr.copy_to_host()

is_c_contiguous()

如果数组是 C-contiguous,则返回 true。

is_f_contiguous()

如果数组是 Fortran-contiguous,则返回 true。

ravel(order='C', stream=0)

在不改变其内容的情况下展平阵列,类似于 numpy.ndarray.ravel()

reshape(*newshape, **kws)

numpy.ndarray.reshape() 类似,重塑阵列而不改变其内容。例:

d_arr = d_arr.reshape(20, 50, order='F')

注意

DeviceNDArray 定义 cuda 阵列接口。

3.3.2 固定内存

numba.cuda.pinned(*arylist)

用于临时固定主机 ndarray 序列的上下文管理器。

numba.cuda.pinned_array(shape, dtype=np.float, strides=None, order='C')

使用固定(页面锁定)的缓冲区分配 np.ndarray。与 np.empty()类似。

3.3.3 流

numba.cuda.stream()

创建表示设备命令队列的 CUDA 流。

CUDA 流有以下方法:

class numba.cuda.cudadrv.driver.Stream(context, handle, finalizer)
auto_synchronize()

一个上下文管理器,它等待此流中的所有命令执行并在退出上下文时提交任何挂起的内存传输。

synchronize()

等待此流中的所有命令执行。这将提交任何挂起的内存传输。

3.3.4 共享内存和线程同步

必要时,可以在设备上分配有限数量的共享内存,以加快对数据的访问。该存储器将在属于给定块的所有线程之间共享(即,可读和可写),并且具有比常规设备存储器更快的访问时间。它还允许线程在给定的解决方案上进行协作。您可以将其视为手动管理的数据缓存。

与传统的动态内存管理不同,内存在内核持续时间内分配一次。

numba.cuda.shared.array(shape, type)

在设备上分配给定 形状类型 的共享数组。必须在设备上调用此函数(即,从内核或设备函数)。 shape是一个整数或整数元组,表示数组的维度,必须是一个简单的常量表达式。* 类型 * 是需要存储在数组中的元素的 Numba 类型。

可以像任何普通设备阵列一样读取和写入返回的类似阵列的对象(例如通过索引)。

常见的模式是让每个线程填充共享数组中的一个元素,然后等待所有线程使用 syncthreads() 完成。

numba.cuda.syncthreads()

同步同一线程块中的所有线程。此函数在传统的多线程编程中实现与 barrier 相同的模式:此函数等待,直到块中的所有线程调用它,此时它将控制权返回给所有调用者。

也可以看看

矩阵乘法示例。

3.3.5 本地记忆

本地内存是每个线程专用的内存区域。当标量局部变量不足时,使用本地内存有助于分配一些暂存区域。与传统的动态内存管理不同,内存在内核持续时间内分配一次。

numba.cuda.local.array(shape, type)

在设备上分配给定 形状类型 的局部数组。 shape是一个整数或整数元组,表示数组的维度,必须是一个简单的常量表达式。* 类型 * 是需要存储在数组中的元素的 Numba 类型。该数组对当前线程是私有的。返回类似于数组的对象,可以像任何标准数组一样读取和写入(例如通过索引)。

3.3.6 恒定记忆

常量内存是一个只读,缓存和片外的内存区域,所有线程都可以访问它,并且是主机分配的。在常量内存中创建数组的方法是使用:

numba.cuda.const.array_like(arr)

基于类似数组 arr ,在常量内存中分配并使数组可访问。

3.3.7 SmartArrays(实验性)

Numba 提供类似数组的数据类型,可自动管理与设备之间的数据移动。在大多数情况下,它可以作为 <cite>numpy.ndarray</cite> 的直接替换,并且由 Numba 的 JIT 编译器支持’host’和’cuda’目标。

class numba.SmartArray(obj=None, copy=True, shape=None, dtype=None, order=None, where='host')

一种支持主机和 GPU 存储的阵列类型。

__init__(obj=None, copy=True, shape=None, dtype=None, order=None, where='host')

在’where’定义的内存空间中构造一个 SmartArray。有效的调用:

  • SmartArray(obj =&lt; array-like object&gt;,copy =&lt; optional-true-or-false&gt;):

    从现有的类似数组的对象创建 SmartArray。 'copy’参数指定是采用还是复制它。

  • SmartArray(shape =&lt; shape&gt;,dtype =&lt; dtype&gt ;, order =&lt; order&gt;)

    在给定典型的 NumPy 数组属性的情况下,从头开始创建新的 SmartArray。

(可选的’where’参数指定最初分配数组的位置。(默认值:‘host’)

get(where='host')

返回给定内存空间中“self”的表示形式。

mark_changed(where='host')

将给定位置标记为已更改,如果需要,则广播更新。

因此, <cite>SmartArray</cite> 对象可以作为函数参数传递给 jit 编译函数。每当执行 cuda.jit 编译的函数时,它将触发向 GPU 的数据传输(除非数据已存在)。但是,在函数完成后,不是将数据传回主机,而是将数据保留在设备上,如果有任何外部引用,则只更新主机端。因此,如果下一个操作是对 cuda.jit 编译函数的另一个调用,则不需要再次传输数据,从而使复合操作更有效(并且即使对于较小的数据大小也使得 GPU 的使用有利)。

3.3.8 解除分配行为

根据每个上下文跟踪所有 CUDA 资源的重新分配。当删除对设备存储器的最后一次引用时,将调度基础存储器以解除分配。释放不会立即发生。它被添加到待处理的解除分配队列中。这种设计有两个好处:

  1. 资源释放 API 可能导致设备同步;因此,打破任何异步执行。延迟重新分配可以避免性能关键代码部分的延迟。
  2. 一些释放错误可能导致所有剩余的解除分配失败。持续的释放错误可能会导致 CUDA 驱动程序级别的严重错误。在某些情况下,这可能意味着 CUDA 驱动程序中的分段错误。在最坏的情况下,这可能导致系统 GUI 冻结,并且只能通过系统重置进行恢复。在释放期间发生错误时,将取消剩余的挂起解除分配。将报告任何释放错误。当进程终止时,CUDA 驱动程序能够通过已终止的进程释放所有已分配的资源。

发生以下事件后,将自动刷新释放队列:

  • 由于内存不足错误导致分配失败。在清除所有解除分配后重试分配。
  • 释放队列已达到其最大大小,默认为 10.用户可以通过设置环境变量 <cite>NUMBA_CUDA_MAX_PENDING_DEALLOCS_COUNT</cite> 来覆盖。例如, <cite>NUMBA_CUDA_MAX_PENDING_DEALLOCS_COUNT = 20</cite> ,将限制增加到 20。
  • 达到挂起释放的资源的最大累积字节大小。这默认为设备内存容量的 20%。用户可以通过设置环境变量 <cite>NUMBA_CUDA_MAX_PENDING_DEALLOCS_RATIO</cite> 来覆盖。例如, <cite>NUMBA_CUDA_MAX_PENDING_DEALLOCS_RATIO = 0.5</cite> 将限制设置为容量的 50%。

有时,需要推迟资源释放,直到代码段结束。大多数情况下,用户希望避免因释放而导致的任何隐式同步。这可以通过使用以下上下文管理器来完成:

numba.cuda.defer_cleanup()

暂时禁用内存释放。使用它来防止资源释放打破异步执行。

例如:

with defer_cleanup():
    # all cleanup is deferred in here
    do_speed_critical_code()
# cleanup can occur here

注意:此上下文管理器可以嵌套。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值