当前位置:网站首页 > 技术博客 > 正文

c++思维导图高清



原文: http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html

Cython 源文件名由模块名称后跟扩展名组成,例如名为 primes 的模块将具有名为的源文件。

与 Python 不同,必须编译 Cython 代码。这发生在两个阶段:

  • A 文件由 Cython 编译为文件。
  • 文件由 C 编译器编译为文件(或 Windows 上的文件)

一旦编写了文件,就可以通过几种方法将其转换为扩展模块。

以下小节介绍了构建扩展模块的几种方法,以及如何将指令传递给 Cython 编译器。

有两种从命令行编译的方法。

  • 命令获取或文件并将其编译为 C / C ++文件。
  • 命令获取或文件并将其编译为 C / C ++文件。然后,它将 C / C ++文件编译为可直接从 Python 导入的扩展模块。

一种方法是使用 Cython 编译器手动编译它,例如:

这将生成一个名为的文件,然后需要使用适合您平台的任何选项使用 C 编译器编译该文件以生成扩展模块。有关这些选项,请查看官方 Python 文档。

另一种可能更好的方法是使用 Cython 提供的 扩展。这种方法的好处是它将提供平台特定的编译选项,就像一个精简的自动工具。

使用您的选项和文件列表运行编译器命令以生成扩展模块。例如:

这将创建一个文件(或 C ++模式下的),对其进行编译,并将生成的扩展模块(或,具体取决于您的平台)放在源文件旁边以进行直接导入(建立“到位”)。 开关另外生成源代码的带注释的 html 文件。

命令接受多个源文件和类似的 glob 模式作为参数,并且还了解运行多个并行构建作业的常用选项。在没有其他选项的情况下调用时,它只会将源文件转换为或文件。传递标志以获取支持选项的完整列表。

更简单的命令行工具仅调用源代码转换器。

在手动编译的情况下,如何编译文件将根据您的操作系统和编译器而有所不同。用于编写扩展模块的 Python 文档应该包含系统的一些详细信息。例如,在 Linux 系统上,它看起来可能类似于:

(需要有包含头文件的路径和要链接的库的路径。)

编译后,将(Windows 的)文件写入目标目录,您的模块可以像任何其他 Python 模块一样导入。请注意,如果您不依赖于或 distutils,您将不会自动受益于 CPython 为消除歧义而生成的特定于平台的文件扩展名,例如 CPython 3.5 的常规 64 位 Linux 安装上的。

Cython 提供的 distutils 扩展允许您将文件直接传递到安装文件中的构造函数。

如果你有一个 Cython 文件要转换为编译扩展名,比如文件名,关联的将是:

要更全面地了解官方 文档。要编译扩展以在当前目录中使用,请使用:

如果您在非标准位置包含文件,则可以将参数传递给:

通常,提供 C 级 API 的 Python 包提供了一种查找必要包含文件的方法,例如,为 NumPy:

注意

使用内存视图或使用导入 NumPy 并不意味着您必须添加 NumPy 包含文件的路径。只有在使用时才需要添加此路径。

尽管如此,您仍然会收到编译器中的以下警告,因为 Cython 使用的是已弃用的 Numpy API:

目前,这只是一个警告,你可以忽略。

如果需要指定编译器选项,要链接的库或其他链接器选项,则需要手动创建实例(请注意,glob 语法仍可用于在一行中指定多个扩展名):

请注意,使用 setuptools 时,您应该在 Cython 之前导入它,因为 setuptools 可能会替换 distutils 中的类。否则,两人可能不同意这里使用的课程。

另请注意,如果使用 setuptools 而不是 distutils,则运行时的默认操作是创建一个压缩的文件,当您尝试从依赖项中使用它们时,这些文件无法与文件一起用于文件包。为防止这种情况,请在的参数中包含。

如果您的选项是静态的(例如,您不需要调用之类的工具来确定它们),您也可以使用文件开头的特殊注释块直接在.pyx 或.pxd 源文件中提供它们。 :

如果您导入多个定义库的.pxd 文件,那么 Cython 会合并库列表,因此这可以按预期工作(与其他选项类似,如上面的)。

如果你有一些用 Cython 包装的 C 文件,并且你想将它们编译到你的扩展中,你可以定义 distutils 参数:

请注意,这些源将添加到当前扩展模块的源列表中。在文件中将其拼写如下:

类有很多选项,可以在 distutils 文档中找到更全面的解释。要了解的一些有用选项是,和,它们指定链接到外部库时在哪里可以找到和库文件。

有时这还不够,你需要更精细的自定义 distutils 。为此,您可以提供自定义函数,以便在 Cython 处理源,依赖项和指令之后但在文件实际进行 Cython 化之前创建最终的对象。该函数有 2 个参数和,其中是作为 Cython 输入的对象,是 ,应该使用所有关键字创建。函数必须返回 2 元组,其中是创建的,是元数据,将在生成的 C 文件的顶部写为 JSON。此元数据仅用于调试目的,因此您可以在其中放置任何内容(只要它可以转换为 JSON)。默认功能(在中定义)是:

如果您将字符串而不是传递给,将是没有来源的。例如,如果执行,将为。

举个例子,这会将作为库添加到每个扩展名中:

Note

如果你并行 Cython 化(使用参数),那么的参数必须是 pickleable。特别是,它不能是 lambda 函数。

函数可以使用额外的参数来允许您自定义构建。

(module_list, exclude=None, nthreads=0, aliases=None, quiet=False, force=False, language=None, exclude_failures=False, options)

将一组源模块编译为 C / C ++文件,并为它们返回 distutils Extension 对象的列表。

<colgroup><col class=”field-name”> <col class=”field-body”></colgroup>| 参数: |

  • module_list - 作为模块列表,传递一个 glob 模式,一个 glob 模式列表或一个扩展对象列表。后者允许您通过常规 distutils 选项单独配置扩展。您还可以传递具有 glob 模式作为其源的扩展对象。然后,cythonize 将解析模式并为每个匹配的文件创建扩展的副本。
  • 排除 - 将 glob 模式作为传递时,可以通过将某些模块名称传递给选项来明确排除它们。
  • nthreads - 并行编译的并发构建数(需要模块)。
  • 别名 - 如果你想使用像这样的编译器指令,但只能在编译时(运行时)知道要使用哪些值,你可以使用别名和在调用 时传递将这些别名映射到 Python 字符串的字典。例如,假设您要使用编译器指令,但此路径并不总是固定,您希望在运行时找到它。然后,您可以执行,在中找到的值,将其作为字符串放入名为的 python 变量中,然后调用。
  • 安静 - 如果为 True,Cython 将不会在编译期间打印错误和警告消息。
  • force - 强制重新编译 Cython 模块,即使时间戳不表示需要重新编译。
  • 语言 - 要全局启用 C ++模式,可以传递。否则,将根据编译器指令在每个文件级别确定。这仅影响基于文件名找到的模块。传入 的扩展实例不会更改。建议使用编译器指令而不是此选项。
  • exclude_failures - 对于广泛的“尝试编译”模式,忽略编译失败并简单地排除失败的扩展,传递。请注意,这仅适用于编译文件,这些文件也可以在不编译的情况下使用。
  • 注释 - 如果,将为每个编译的或文件生成一个 HTML 文件。与普通的 C 代码相比,HTML 文件指示了每个源代码行中的 Python 交互量。它还允许您查看为每行 Cython 代码生成的 C / C ++代码。当优化速度函数以及确定何时 释放 GIL时,此报告非常有用:通常,块可能只包含“白色”代码。参见 中的实例确定添加类型 或 Primes的位置。
  • compiler_directives - 允许在中设置编译器指令,如下所示:。参见 编译器指令 。

    || —- | —- |

要自动编译多个 Cython 文件而不显式列出所有这些文件,可以使用 glob 模式:

如果通过传递它们,也可以在对象中使用 glob 模式:

强烈建议您分发生成的文件以及 Cython 源,以便用户可以安装模块而无需使用 Cython。

还建议在您分发的版本中默认不启用 Cython 编译。即使用户安装了 Cython,他/她可能也不想仅仅使用它来安装模块。此外,安装的版本可能与您使用的版本不同,并且可能无法正确编译您的源。

这只是意味着您附带的文件将只是生成的 <cite>.c</cite> 文件中的正常 distutils 文件,对于我们将要使用的基本示例:

通过更改扩展模块源的文件扩展名,可以很容易地与结合使用:

如果您有许多扩展并希望避免声明中的额外复杂性,您可以使用它们的正常 Cython 源声明它们,然后在不使用 Cython 时调用以下函数而不是来调整 Extensions 中的源列表:

另一个选择是使 Cython 成为系统的设置依赖项,并使用 Cython 的 build_ext 模块作为构建过程的一部分运行:

如果要公开库的 C 级接口以便其他库从 cimport,请使用 package_data 来安装文件,例如:

如果这些文件包含纯粹的外部库声明,则它们不需要具有相应的模块。

请记住,如果使用 setuptools 而不是 distutils,则运行时的默认操作是创建一个压缩的文件,当您尝试从依赖包中使用它们时,这些文件无法与文件一起用于文件。为防止这种情况,请在的参数中包含。

在某些情况下,将多个 Cython 模块(或其他扩展模块)链接到单个二进制文件中可能很有用,例如:将 Python 嵌入另一个应用程序时。这可以通过 CPython 的 inittab 导入机制来完成。

创建一个新的 C 文件以集成扩展模块并将其添加到它:

如果您只定位 Python 3.x,只需使用作为前缀。

然后,对于每个模块,声明其模块 init 函数如下,将替换为模块的名称:

在 C ++中,将它们声明为。

如果您不确定模块初始化函数的名称,请参阅生成的模块源文件并查找以开头的函数名称。

接下来,在使用从应用程序代码启动 Python 运行时之前,需要使用 C-API 函数在运行时初始化模块,再次插入每个模块的名称:

这样可以为嵌入式扩展模块进行正常导入。

为了防止连接的二进制文件将所有模块初始化函数导出为公共符号,如果在 C 编译模块 C 文件时定义了宏,则 Cython 0.28 及更高版本可以隐藏这些符号。

另请查看 cython_freeze 工具。它可以生成必要的样板代码,用于将一个或多个模块链接到单个 Python 可执行文件中。

为了在开发期间构建 Cython 模块而不在每次更改后显式运行,您可以使用:

这允许您在 Py​​thon 尝试导入的每个上自动运行 Cython。只有在没有额外的 C 库且不需要特殊的构建设置的情况下,才应该将它用于简单的 Cython 构建。

也可以编译正在导入的新模块(包括标准库和已安装的软件包)。要使用此功能,只需告诉:

在 Cython 无法编译 Python 模块的情况下,将回退到加载源模块。

请注意,建议不要让在最终用户端构建代码,因为它会挂钩到导入系统。满足最终用户的最佳方式是以轮包装格式提供预先构建的二进制包。

函数可以使用几个参数来影响 Cython 或 Python 文件的编译。

(pyximport=True, pyimport=False, build_dir=None, build_in_temp=True, setup_args=None, reload_support=False, load_py_module_on_import_failure=False, inplace=False, language_level=None)

pyxinstall 的主要入口点。

调用此方法在元数据路径中为单个 Python 进程安装导入挂钩。如果您希望在使用 Python 时安装它,请将其添加到(如上所述)。

<colgroup><col class=”field-name”> <col class=”field-body”></colgroup>| Parameters: |

  • pyximport - 如果设置为 False,则不尝试导入文件。
  • pyimport - 您可以传递以在元路径中安装导入挂钩。但请注意,它是相当实验性的,对于某些文件和软件包根本不起作用,并且由于搜索和编译而会大大减慢您的导入速度。使用风险由您自己承担。
  • build_dir - 默认情况下,已编译的模块最终将位于用户主目录的目录中。传递一个不同的路径作为将覆盖此。
  • build_in_temp - 如果,将在本地生成 C 文件。使用复杂的依赖项和调试变得更加容易。这主要可能会干扰同名的现有文件。
  • setup_args - 分布参数的字典。见。
  • reload_support - 支持动态,例如在 Cython 代码更改后。当无法覆盖先前加载的模块文件时,该帐户可能会出现附加文件。
  • load_py_module_on_import_failure - 如果文件的编译成功,但后续导入由于某种原因失败,请使用普通模块而不是编译模块重试导入。请注意,这可能会导致在导入期间更改系统状态的模块出现不可预测的结果,因为第二次导入将在导入已编译模块失败后系统处于的任何状态下重新运行这些修改。
  • 就地 - 在源文件旁边安装已编译的模块(Linux 的和 Mac 的)。
  • language_level - 要使用的源语言级别:2 或 3.默认情况下,使用.py 文件的当前 Python 运行时的语言级别和文件的 Py2。

    || —- | —- |

由于内部不使用,因此它当前需要不同的依赖设置。可以声明您的模块依赖于多个文件(可能是和文件)。如果您的 Cython 模块名为,因此具有文件名,那么您应该在名为的同一目录中创建另一个文件。 文件可以是文件名列表或“globs”(如或)。每个文件名或 glob 必须在单独的行上。在决定是否重建模块之前,Pyximport 将检查每个文件的文件日期。为了跟踪已经处理了依赖关系的事实,Pyximport 更新了“.pyx”源文件的修改时间。未来版本可能会做更复杂的事情,比如直接通知依赖关系的 distutils。

不使用。因此,不可能在 Cython 文件的顶部使用编译器指令或将 Cython 代码编译为 C ++。

Pyximport 不会让您控制 Cython 文件的编译方式。通常默认值很好。如果你想用半-C,半 Cython 编写你的程序并将它们构建到一个库中,你可能会遇到问题。

Pyximport 不会隐藏导入过程生成的 Distutils / GCC 警告和错误。可以说,如果出现问题以及原因,这将为您提供更好的反馈。如果没有出现任何问题,它会给你一种温暖的模糊感觉,pyximport 确实按照预期重建你的模块。

选项提供基本模块重新加载支持。请注意,这将为每个构建生成一个新的模块文件名,从而最终将多个共享库随时间加载到内存中。 CPython 对重新加载共享库的支持有限,参见 PEP 489 。

Pyximport 将您的文件和特定于平台的二进制文件放入一个单独的构建目录,通常是。要将其复制回包层次结构(通常在源文件旁边)以进行手动重用,可以传递选项。

也可以用类似于 SciPy 的的方式编译 Cython。例如:

未绑定的变量会自动从周围的本地和全局范围中提取,并且编译结果将被缓存以便有效地重复使用。

Sage 笔记本允许通过在单元格顶部键入并对其进行评估来透明地编辑和编译 Cython 代码。 Cython 单元格中定义的变量和函数将导入到正在运行的会话中。有关详细信息,请查看 Sage 文档。

您可以通过指定以下指令来定制 Cython 编译器的行为。

使用 Cython 可以在笔记本单元中编译代码。为此你需要加载 Cython 魔法:

然后,您可以通过在其上面写入来定义 Cython 单元格。像这样:

请注意,每个单元格将编译为单独的扩展模块。因此,如果您在 Cython 单元格中使用包,则必须在同一单元格中导入此包。在先前的单元格中导入包是不够的。如果你不遵守,Cython 会告诉你编译时有“未定义的全局名称”。

然后将单元格的全局名称(顶级函数,类,变量和模块)加载到笔记本的全局命名空间中。所以最后,它的行为就好像你执行了一个 Python 单元格。

下面列出了 Cython 魔术的其他允许参数。您也可以通过在 IPython 或 Jupyter 笔记本中键入来查看它们。

| -a,-annotate | 生成源的彩色 HTML 版本。 || -annotate-fullc | 生成源的彩色 HTML 版本,其中包括整个生成的 C / C ++代码。 || - +,-cplus | 输出 C ++而不是 C 文件。 || -f,-force | 强制编译新模块,即使以前编译过源也是如此。 || -3 | 选择 Python 3 语法 || -2 | 选择 Python 2 语法 || -c = COMPILE_ARGS,-compile-args = COMPILE_ARGS | 通过 extra_compile_args 传递给编译器的额外标志。 || -link-args LINK_ARGS | 通过 extra_link_args 传递给链接器的额外标志。 || -l LIB,-lib LIB | 添加库以链接扩展名(可以多次指定)。 || -L dir | 添加库目录列表的路径(可以多次指定)。 || - 我包括,包括 INCLUDE | 添加包含目录列表的路径(可以多次指定)。 || -S,-src | 添加 src 文件列表的路径(可以多次指定)。 || -n NAME, - name NAME | 指定 Cython 模块的名称。 || -pgo | 在 C 编译器中启用配置文件引导优化。编译单元格两次并在其间执行以生成运行时配置文件。 || -verbose | 打印调试信息,如生成的.c / .cpp 文件位置和调用的精确 gcc / g ++命令。 |

在调用之前,可以在中设置编译器选项,如下所示:

以下是可用的选项:

= True

是否在 Python 扩展中包含 docstring。如果为 False,则二进制大小将更小,但任何类或函数的属性将为空字符串。

= False

将源代码位置嵌入到函数和类的文档字符串中。

= True

将原始源代码逐行复制到生成的代码文件中的 C 代码注释中,以帮助理解输出。这也是覆盖率分析所必需的。

= False

在退出时为每个模块删除全局变量以进行垃圾回收。 0:无,1 +:实习对象,2 +:cdef 全局,3 +:类型对象主要用于降低 Valgrind 中的噪声,仅在进程退出时执行(当所有内存都将被回收时)。

= True

tp_clear()应该将对象字段设置为 None 而不是将它们清除为 NULL 吗?

= False

生成带注释的 HTML 版本的输入源文件,以进行调试和优化。这与中的参数具有相同的效果。

= False

这将在第一次发生错误时中止编译,而不是试图继续进行并打印更多错误消息。

= False

将所有警告变为错误。

= True

使未知名称成为错误。 Python 在运行时遇到未知名称时会引发 NameError,而此选项会使它们成为编译时错误。如果您想要完全兼容 Python,则应禁用此选项以及“cache_builtins”。

= True

使未初始化的局部变量引用编译时错误。 Python 在运行时引发 UnboundLocalError,而此选项使它们成为编译时错误。请注意,此选项仅影响“python 对象”类型的变量。

= True

当是 C 整数类型时,这将把形式的语句转换为,并且可以确定方向(即步骤的符号)。警告:如果范围导致 i 的分配溢出,则可能会更改语义。具体来说,如果设置了此选项,则在输入循环之前将引发错误,而如果没有此选项,则循环将执行,直到遇到溢出值。

= True

在模块初始化时,仅对内置名称执行一次查找。如果在初始化期间找不到它使用的内置名称,这将阻止导入模块。默认为 True。请注意,在 Python 3.x 中构建时,一些遗留的内置函数会自动从 Python 2 名称重新映射到 Cython 的 Python 3 名称,这样即使启用此选项,它们也不会妨碍它们。

= True

生成分支预测提示以加快错误处理等。

= False

如果 cpdef 函数为 foo,则启用此选项以允许写入来覆盖定义,代价是每次调用时额外的字典查找。如果这是假的,它只生成 Python 包装器而不进行覆盖检查。

= None

是否嵌入 Python 解释器,用于制作独立的可执行文件或从外部库调用。这将提供一个 C 函数,它初始化解释器并执行该模块的主体。有关具体示例,请参见此演示。如果为 true,则初始化函数是 C main()函数,但此选项也可以设置为非空字符串以显式提供函数名称。默认值为 False。

= False

允许从没有 pxd 文件的 pyx 文件中导入。

= 8

缓冲区的最大维数 - 设置低于 numpy 中的维数,因为切片按值传递并涉及大量复制。

= 8

要保留在空闲列表中的函数闭包实例数(0:没有空闲列表)

编译器指令是影响 Cython 代码行为的指令。以下是当前支持的指令列表:

(True / False)

Controls whether free functions behave more like Python’s CFunctions (e.g. ) or, when set to True, more like Python’s functions. When enabled, functions will bind to an instance when looked up as a class attribute (hence the name) and will emulate the attributes of Python functions, including introspections like argument names and annotations. Default is False.

(True / False)

If set to False, Cython is free to assume that indexing operations ([]-operator) in the code will not cause any IndexErrors to be raised. Lists, tuples, and strings are affected only if the index can be determined to be non-negative (or if is False). Conditions which would normally trigger an IndexError may instead cause segfaults or data corruption if this is set to False. Default is True.

(True / False)

In Python, arrays and sequences can be indexed relative to the end. For example, A[-1] indexes the last value of a list. In C, negative indexing is not supported. If set to False, Cython is allowed to neither check for nor correctly handle negative indices, possibly causing segfaults or data corruption. If bounds checks are enabled (the default, see above), negative indexing will usually raise an for indices that Cython evaluates itself. However, these cases can be difficult to recognise in user code to distinguish them from indexing or slicing that is evaluated by the underlying Python array or sequence object and thus continues to support wrap-around indices. It is therefore safest to apply this option only to code that does not process negative indices at all. Default is True.

(True / False)

If set to True, Cython checks that a memoryview is initialized whenever its elements are accessed or assigned to. Setting this to False disables these checks. Default is True.

(True / False)

If set to False, Cython is free to assume that native field accesses on variables typed as an extension type, or buffer accesses on a buffer variable, never occurs when the variable is set to . Otherwise a check is inserted and the appropriate exception is raised. This is off by default for performance reasons. Default is False.

(True / False)

If set to True, raise errors on overflowing C integer arithmetic operations. Incurs a modest runtime penalty, but is much faster than using Python ints. Default is False.

(True / False)

If set to True, and overflowcheck is True, check the overflow bit for nested, side-effect-free arithmetic expressions once rather than at every step. Depending on the compiler, architecture, and optimization settings, this may help or hurt performance. A simple suite of benchmarks can be found in . Default is True.

(True / False)

If set to True, Cython will embed a textual copy of the call signature in the docstring of all Python visible functions and classes. Tools like IPython and epydoc can thus display the signature, which cannot otherwise be retrieved after compilation. Default is False.

(True / False)

If set to False, Cython will adjust the remainder and quotient operators C types to match those of Python ints (which differ when the operands have opposite signs) and raise a when the right operand is 0. This has up to a 35% speed penalty. If set to True, no checks are performed. See CEP 516. Default is False.

(True / False)

If set to True, Cython will emit a runtime warning whenever division is performed with negative operands. See CEP 516. Default is False.

(True / False)

Avoid the and when constructing functions/methods which take zero or one arguments. Has no effect on special methods and functions with more than one argument. The and signatures provide faster calling conventions but disallow the use of keywords.

(True / False)

Write hooks for Python profilers into the compiled C code. Default is False.

(True / False)

Write line tracing hooks for Python profilers or coverage reporting into the compiled C code. This also enables profiling. Default is False. Note that the generated module will not actually use line tracing, unless you additionally pass the C macro definition to the C compiler (e.g. using the distutils option ). Define to also include functions and sections.

(True / False)

Infer types of untyped variables in function bodies. Default is None, indicating that only safe (semantically-unchanging) inferences are allowed. In particular, inferring integral types for variables used in arithmetic expressions is considered unsafe (due to possible overflow) and must be explicitly requested.

(2/3/3str)

Globally set the Python language level to be used for module compilation. Default is compatibility with Python 2. To enable Python 3 source code semantics, set this to 3 (or 3str) at the start of a module or pass the “-3” or “–3str” command line options to the compiler. The option enables Python 3 semantics but does not change the type and unprefixed string literals to when the compiled code runs in Python 2.x. Note that cimported files inherit this setting from the module being compiled, unless they explicitly set their own language level. Included source files always inherit this setting.

(bytes / str / unicode)

Globally set the type of an implicit coercion from char* or std::string.

(ascii, default, utf-8, etc.)

Globally set the encoding to use when implicitly coercing char* or std:string to a unicode object. Coercion from a unicode object to C type is only allowed when set to or , the latter being utf-8 in Python 3 and nearly-always ascii in Python 2.

(True / False)

Enables the attribute cache for extension types in CPython by setting the type flag . Default is True, meaning that the cache is enabled for Cython implemented types. To disable it explicitly in the rare cases where a type needs to juggle with its internally without paying attention to cache consistency, this option can be set to False.

(True / False)

Whether to print tracebacks when suppressing unraisable exceptions.

(True / False)

PEP 492 specifies that async-def coroutines must not be iterable, in order to prevent accidental misuse in non-async contexts. However, this makes it difficult and inefficient to write backwards compatible code that uses async-def coroutines in Cython but needs to interact with async Python code that uses the older yield-from syntax, such as asyncio before Python 3.5. This directive can be applied in modules or selectively as decorator on an async-def coroutine to make the affected coroutine(s) iterable and thus directly interoperable with yield-from.

(True / False)

Whether to expand chained if-else statements (including statements like ) into C switch statements. This can have performance benefits if there are lots of values but cause compiler errors if there are any duplicate values (which may not be detectable at Cython compile time for all C constants). Default is True.

(True / False)

Cython can generate code that optimistically checks for Python method objects at call time and unpacks the underlying function to call it directly. This can substantially speed up method calls, especially for builtins, but may also have a slight negative performance impact in some cases where the guess goes completely wrong. Disabling this option can also reduce the code size. Default is True.

所有警告指令都采用 True / False 作为打开/关闭警告的选项。

(default False)

Warns about any variables that are implicitly declared without a declaration

(default True)

Warns about code paths that are statically determined to be unreachable, e.g. returning twice unconditionally.

(default False)

Warns about use of variables that are conditionally uninitialized.

(default False)

Warns about unused variables and declarations

(default False)

Warns about unused function arguments

(default False)

Warns about unused assignment to the same name, such as

(default True)

Warns about multiple variables declared on the same line with at least one pointer type. For example - which, as in C, declares as a pointer, as a value type, but could be mininterpreted as declaring two pointers.

全球

可以通过文件顶部附近的特殊标题注释设置编译器指令,如下所示:

注释必须出现在任何代码之前(但可以出现在其他注释或空格之后)。

也可以使用-X 开关在命令行上传递指令:

在命令行上传递的指令将覆盖在头注释中设置的指令。

本地

对于本地块,您需要使用特殊的内置模块:

然后你可以使用指令作为装饰器或在 with 语句中,如下所示:

警告

这两种设置指令的方法是而不是,它们使用-X 选项覆盖命令行上的指令。

在 中

通过将关键字参数传递给,也可以在文件中设置编译器指令:

这将覆盖字典中指定的默认指令。请注意,如上所述的显式每文件或本地指令优先于传递给的值。

原文: http://docs.cython.org/en/latest/src/userguide/early_binding_for_speed.html

作为一种动态语言,Python 鼓励一种编程风格,即在方法和属性方面考虑类和对象,而不是它们适合类层次结构。

这可以使 Python 成为一种非常轻松和舒适的快速开发语言,但需要付出代价 - 管理数据类型的“繁文缛节”会被转储到解释器上。在运行时,解释器在搜索命名空间,获取属性以及解析参数和关键字元组方面做了大量工作。与“早期绑定”语言(如 C ++)相比,这种运行时“后期绑定”是 Python 相对缓慢的主要原因。

然而,使用 Cython,通过使用“早期绑定”编程技术可以获得显着的加速。

例如,考虑以下(愚蠢)代码示例:

在方法中,对和方法的调用包含大量的 Python 开销。

但是,在 Cython 中,在 Cython 代码中发生调用的情况下,可以消除大量的开销。例如:

这里,在 Rectangle 扩展类中,我们定义了两种不同的区域计算方法,即高效的 C 方法,以及 Python 可调用的方法,它作为的薄包装器。还要注意函数我们如何’早期绑定’,通过声明显式赋予 Rectangle 类型的局部变量。通过使用此声明,我们获得了访问更有效的 C-callable 方法的能力,而不仅仅是动态分配给。

但是 Cython 通过允许我们声明双访问方法 - 可以在 C 级别高效调用的方法,但也可以以 Python 访问开销为代价从纯 Python 代码访问,从而再次为我们提供了更多的简单性。考虑以下代码:

在这里,我们只有一个区域方法,声明为 ,使其可以作为 C 函数有效地调用,但仍然可以从纯 Python(或后期绑定的 Cython)代码访问。

如果在 Cython 代码中,我们有一个已经’早期绑定’的变量(即,显式声明为 Rectangle 类型,或者转换为 Rectangle 类型),那么调用其 area 方法将使用高效的 C 代码路径并跳过 Python 开销。但是如果在 Cython 或常规 Python 代码中我们有一个存储 Rectangle 对象的常规对象变量,那么调用 area 方法将需要:

  • 区域方法的属性查找
  • 打包参数的元组和关键字的 dict(在这种情况下都是空的)
  • 使用 Python API 调用该方法

并且在区域方法本身内:

  • 解析元组和关键字
  • 执行计算代码
  • 将结果转换为 python 对象并返回它

因此,在 Cython 中,通过在声明和转换变量中使用强类型来实现大规模优化是可能的。对于使用方法调用的紧密循环,以及这些方法是纯 C 的情况,差异可能很大。

原文: http://docs.cython.org/en/latest/src/userguide/wrapping_CPlusPlus.html

Cython 对大多数 C ++语言都有本机支持。特别:

  • 可以使用和关键字动态分配 C ++对象。
  • C ++对象可以进行堆栈分配。
  • 可以使用 new 关键字声明 C ++类。
  • 支持模板化的类和函数。
  • 支持重载功能。
  • 支持重载 C ++运算符(例如 operator +,operator [],…)。

包装 C ++文件的一般过程现在可以描述如下:

  • 在脚本中指定 C ++语言,或在源文件中指定本地。
  • 使用块和(如果存在)C ++命名空间名称创建一个或多个文件。在这些块中:
    • 将类声明为块
    • 声明公共名称(变量,方法和构造函数)
  • 它们位于一个或多个扩展模块(文件)中。

这是一个很小的 C ++ API,我们将在本文档中将其作为示例。我们假设它将位于名为的头文件中:

以及名为的文件中的实现:

这非常愚蠢,但应该足以证明所涉及的步骤。

包装 C ++类的过程与包装普通 C 结构的过程非常类似,只需添加几个。让我们从创建基本块开始:

这将使得 Rectangle 的 C ++类 def 可用。请注意名称空间声明。命名空间仅用于创建对象的完全限定名称,并且可以嵌套(例如)或甚至引用类(例如在 MyClass 上声明静态成员)。

使用 cdef cppclass 声明类

现在,让我们从块中将 Rectangle 类添加到此 extern - 只需从 Rectangle.h 复制类名并调整 Cython 语法,现在它变为:

添加公共属性

我们现在需要声明在 Cython 上使用的属性和方法。我们将这些声明放在一个名为的文件中。您可以将其视为可由 Cython 读取的头文件:

请注意,构造函数声明为“except +”。如果 C ++代码或初始内存分配由于失败而引发异常,这将使 Cython 安全地引发适当的 Python 异常(见下文)。如果没有此声明,Cython 将不会处理源自构造函数的 C ++异常。

我们使用这些线:

包含来自的 C ++代码。也可以指定为源的 distutils。为此,您可以在(不是)文件的顶部添加此指令:

请注意,使用时,指定的路径相对于当前文件,但如果使用 distutils 指令,则路径相对于。如果要在运行时发现源的路径,可以使用功能的参数。

用包装的 C ++类声明一个 var

我们将创建一个名为的文件来构建我们的包装器。我们使用的是以外的名称,但如果您希望为包装器提供与 C ++类相同的名称,请参阅 解决命名冲突 的部分。

在其中,我们使用 cdef 使用 C ++ 语句声明类的 var:

这条线:

是向 Cython 表明这个文件必须编译为 C ++。

只要它具有“默认”构造函数,也可以声明堆栈分配的对象:

请注意,与 C ++一样,如果类只有一个构造函数并且它是一个无效的,那么就没有必要声明它。

此时,我们已经将我们的 pyx 文件的命名空间暴露给 C ++ Rectangle 类型的接口。现在,我们需要从外部 Python 代码访问它(这是我们的全部观点)。

常见的编程实践是创建一个 Cython 扩展类型,它将 C ++实例作为属性保存并创建一堆转发方法。所以我们可以将 Python 扩展类型实现为:

我们终于得到它了。从 Python 的角度来看,这种扩展类型的外观和感觉就像本机定义的 Rectangle 类一样。需要注意的是,如果要提供属性访问权限,可以实现一些属性:

Cython 使用 nullary 构造函数初始化 cdef 类的 C ++类属性。如果要包装的类没有构造函数,则必须存储指向包装类的指针并手动分配和取消分配它。一个方便和安全的地方是 <cite>cinit</cite> 和 <cite>dealloc</cite> 方法,保证在创建和删除 Python 实例时只调用一次。

要编译 Cython 模块,必须有一个文件:

运行

要测试它,打开 Python 解释器:

我们在这里描述了上面教程中没有讨论过的所有 C ++特性。

重载非常简单。只需使用不同的参数声明方法并使用其中任何一个:

Cython 使用 C ++命名来重载运算符:

请注意,如果有一个 指针 到 C ++对象,则必须进行解除引用以避免执行指针算术而不是对对象本身进行算术运算:

C ++允许嵌套类声明。类声明也可以嵌套在 Cython 中:

请注意,嵌套类使用声明但没有,因为它已经是声明部分的一部分。

Cython 尝试使其语法尽可能接近标准 Python。因此,某些 C ++运算符(如 preincrement 或解除引用运算符)不能与 C ++使用相同的语法。 Cython 提供了在特殊模块中替换这些运算符的函数。提供的功能是:

  • 用于解除引用的。 将生成 C ++代码
  • 用于预增量。 将生成 C ++代码。类似地,和。
  • 逗号运算符的。 将生成 C ++代码。

这些功能需要被引导。当然,可以使用来获得更短且更易读的功能。例如:。

为了完整起见,还值得一提的是,它也可以写成。

Cython 使用括号语法进行模板化。包装 C ++向量的一个简单示例:

可以将多个模板参数定义为列表,例如或。可以通过写来指示可选的模板参数。如果 Cython 需要显式引用不完整模板实例化的默认模板参数的类型,它将写入,因此如果类为其模板参数提供 typedef,则最好在此处使用该名称。

模板函数的定义与类模板类似,模板参数列表位于函数名称后面:

C ++标准库的大多数容器已在位于 / Cython / Includes / libcpp 中的 pxd 文件中声明。这些容器是:deque,list,map,pair,queue,set,stack,vector。

例如:

/ Cython / Includes / libcpp 中的 pxd 文件也是如何声明 C ++类的好例子。

STL 容器强制执行相应的 Python 内置类型。转换是通过赋值给类型变量(包括类型化函数参数)或通过显式强制转换来触发的,例如:

可以使用以下强制措施:

| Python type =&gt; | C ++类型 | =&GT; Python 类型 || —- | —- | —- || 字节 | 的 std :: string | bytes || 迭代 | 的 std ::矢量 | 名单 || iterable | 的 std ::名单 | list || iterable | 的 std ::设为 | 组 || 可迭代的(len 2) | 的 std ::对 | 元组(len 2) |

所有转换都会创建一个新容器并将数据复制到其中。容器中的物品自动转换成相应的类型,包括递归地转换容器内的容器,例如容器。字符串映射的 C ++向量。

通过语法(包括列表推导)支持对 stl 容器(或实际上任何具有和方法的类返回支持递增,解除引用和比较的对象的迭代)的迭代。例如,人们可以写:

如果未指定循环目标变量,则 类型推断 使用类型的赋值。

注意

支持切片 stl 容器,你可以做,但与指针切片不同,它将创建一个临时的 Python 对象并迭代它。因此使迭代非常缓慢。出于性能原因,您可能希望避免切片 C ++容器。

如果您的扩展类型使用默认构造函数(不传递任何参数)实例化包装的 C ++类,您可以通过将生命周期处理直接绑定到 Python 包装器对象的生命周期来简化生命周期处理。您可以声明一个实例,而不是指针属性:

Cython 将自动生成在创建 Python 对象时实例化 C ++对象实例的代码,并在 Python 对象被垃圾回收时删除它。

Cython 不能抛出 C ++异常,或者用 try-except 语句捕获它们,但是可以将函数声明为可能引发 C ++异常并将其转换为 Python 异常。例如,

这会将 try 和 C ++错误转换为适当的 Python 异常。根据下表执行转换(从 C ++标识符中省略前缀):

| C ++ | 蟒蛇 || —- | —- || | || | || | || | || | || | || | || | || | || | || (所有其他人) | |

保留消息(如果有)。请注意,C ++ 可以表示 EOF,但是没有足够的信息供 Cython 识别,因此请注意 IO 流上的异常掩码。

这将捕获任何 C ++错误并在其位置引发 Python MemoryError。 (任何 Python 异常在这里都有效。)

如果 something_dangerous 引发了 C ++异常,那么将调用 raise_py_error,这允许自定义 C ++到 Python 错误“翻译”。如果 raise_py_error 实际上没有引发异常,则会引发 RuntimeError。

还有一种特殊的形式:

对于那些可能引发 Python 或 C ++异常的函数。

如果 Rectangle 类具有静态成员:

你可以使用 Python @staticmethod 装饰器声明它,即:

Cython 支持使用标准语法声明左值引用。但请注意,没有必要将 extern 函数的参数声明为引用(const 或其他),因为它对调用者的语法没有影响。

虽然 Cython 没有关键字,但是没有用显式输入的 Cython 局部变量是从 右侧的类型中推断出所有 的分配(参见 编译指令 )。在处理返回复杂,嵌套,模板化类型的函数时,这尤其方便,例如:

(当然,对于支持迭代协议的对象,语法是首选。)

Cython 支持运算符。

来自 cython.operator cimport typeid

运算符返回类型的对象。

如果要将 type_info 值存储在 C 变量中,则需要将其存储为指针而不是引用:

如果将无效类型传递给,它将抛出异常,该异常在 Python 中转换为异常。

中提供了另一个与 C ++ 11 兼容的 RTTI 相关类。

可以在文件中声明它们,而不是在源文件中指定语言和源:

Cython 将生成并编译文件(来自),然后它将编译(类的实现)并将两个目标文件一起链接到 Linux 上的或在 Windows 上,然后可以使用在 Python 中导入(如果忘记链接,则在 Python 中导入库时将丢失符号)。

请注意,选项对传递给的用户提供的 Extension 对象没有影响。它仅用于按文件名找到的模块(如上例所示)。

Cython 版本中最大 0.21 的功能无法识别选项,需要将其指定为描述扩展名的选项,然后由处理,如下所示:

选项也可以直接从源文件传递,这通常是可取的(并覆盖任何全局选项)。从版本 0.17 开始,Cython 还允许以这种方式将外部源文件传递到命令。这是一个简化的 setup.py 文件:

在.pyx 源文件中,将其写入第一个注释块,在任何源代码之前,以 C ++模式编译它并将其静态链接到代码文件:

Note

使用 distutils 指令时,路径相对于 distutils 运行的工作目录(通常是所在的项目根目录)。

要手动编译(例如使用),可以使用命令行实用程序生成 C ++ 文件,然后将其编译为 python 扩展。使用选项打开命令的 C ++模式。

每当生成 C ++代码时,Cython 都会生成函数的声明和调用,假设这些函数是 C ++(即,未声明为。如果 C 函数具有 C ++入口点,这是可以的,但如果它们只是 C,那么你将遇到障碍。如果你有一个 C ++ Cython 模块需要调用 pure-C 函数,你需要编写一个小的 C ++ shim 模块:

  • 包括 extern“C”块中所需的 C 头
  • 包含 C ++中的最小转发函数,每个函数都调用相应的 pure-C 函数

C ++允许返回引用的函数为 left-values。 Cython 目前不支持此功能。 也不被视为左值。

原文: http://docs.cython.org/en/latest/src/userguide/fusedtypes.html

融合类型允许您有一个可以引用多种类型的类型定义。这允许您编写一个静态类型的 cython 算法,该算法可以对多种类型的值进行操作。因此,融合类型允许泛型编程,类似于 C ++中的模板或 Java / C#等语言中的泛型。

注意

目前不支持融合类型作为扩展类型的属性。只能使用融合类型声明变量和函数/方法参数。

这给出了:

将“融合型”“专门化”为,而将专门化为。

融合类型可以声明如下:

这声明了一个名为的新类型,它可以是和 a 。或者,声明可以写成:

只有名称可用于组成类型,但它们可以是任何(非融合)类型,包括 typedef。即可以写:

融合类型可用于声明函数或方法的参数:

如果在参数列表中多次使用相同的融合类型,则融合类型的每个特化必须相同:

在这种情况下,两个参数的类型都是 int 或 double(根据前面的示例)。但是,因为这些参数使用相同的融合类型,所以和都专用于相同类型。因此,对于每个可能的有效调用,此函数都返回 True。但是你可以混合融合类型:

其中和是不同的融合类型。这将为和中包含的所有类型组合生成专门的代码路径。

请注意,仅数字类型的特化可能不是非常有用,因为通常可以依赖于类型的提升。但是,对于内存的数组,指针和类型化视图,情况并非如此。的确,有人可能写道:

请注意,在 Cython 0.20.x 及更早版本中,当类型签名中的多个内存视图使用融合类型时,编译器会生成所有类型组合的完整交叉积。

这对于大多数用户来说是出乎意料的,不太可能是期望的,并且与其他结构化类型声明(例如融合类型的 C 数组)不一致,这些声明被认为是相同的类型。因此在 Cython 0.21 中进行了更改,以便对融合类型的所有内存视图使用相同的类型。为了获得原始行为,只需在不同的名称下声明相同的融合类型,然后在声明中使用它们:

要在较旧的 Cython 版本(0.21 之前版本)中仅获得相同类型,可以使用:

您可以通过两种方式选择特化(具有特定或专用(即非融合)参数类型的函数实例):通过索引或通过调用。

您可以使用类型索引函数以获得某些特化,即:

如果使用融合类型作为基类型,这将意味着基类型是融合类型,因此基类型需要专门化:

也可以使用参数调用融合函数,其中自动计算调度:

对于从 Cython 调用的或函数,这意味着在编译时计算出特化。对于函数,在运行时对参数进行类型检查,并执行尽力而为的方法来确定需要哪种特化。这意味着如果没有找到特化,这可能会导致运行时。如果函数的类型未知,则函数的处理方式与函数的处理方式相同(例如,如果它是外部的,并且没有 cimport)。

自动调度规则通常如下所示,按优先顺序排列:

  • 试着找到完全匹配
  • 选择最大的相应数值类型(最大浮点数,最大复数,最大 int)

为方便起见,有一些内置的融合类型,它们是:

融合的和函数可以转换或分配给 C 函数指针,如下所示:

可以基于融合参数的特化来做出决定。修剪错误条件以避免无效代码。可以检查,和和以查看融合类型是否等于某个其他非融合类型(检查专业化),或使用和[COD5 判断专门化是否是另一组类型(指定为融合类型)的一部分。例如:

获取和释放 GIL 可以通过编译时已知的条件来控制(参见 条件获取/释放 GIL)。

当与融合类型结合使用时,这是最有用的。融合类型函数可能必须处理 cython 本机类​​型(例如 cython.int 或 cython.double)和 python 类型(例如对象或字节)。条件获取/释放 GIL 提供了一种运行相同代码的方法,无论是发布 GIL(对于 cython 本机类​​型)还是持有 GIL(对于 python 类型):

最后,来自或函数的函数对象具有 signatures 属性,该属性将签名字符串映射到实际的专用函数。这可能对检查有用。列出的签名字符串也可以用作融合函数的索引,但索引格式可能会在 Cython 版本之间发生变化:

通常最好像这样索引,但是:

虽然后者将从 Python 空间中选择和的最大类型,因为它们不是类型标识符,而是内置类型。但是,通过和可以解决这个问题。

对于来自 python 空间的 memoryview 索引,我们可以执行以下操作:

使用例如同样的方法也是如此。 。

原文: http://docs.cython.org/en/latest/src/userguide/pypy.html

Cython 对 cpyext 有基本支持,cpyext 是 PyPy 中模拟 CPython 的 C-API 的层。这是通过使生成的 C 代码在 C 编译时适应来实现的,因此生成的代码将在 CPython 和 PyPy 中编译都不变。

但是,除了 Cython 可以在内部覆盖和调整之外,cpyext C-API 仿真还涉及到 CPython 中对用户代码有明显影响的真实 C-API 的一些差异。此页面列出了主要的差异以及处理它们的方法,以便编写在 CPython 和 PyPy 中都有效的 Cython 代码。

PyPy 的一般设计差异是运行时内部不使用引用计数,但始终是垃圾收集器。仅通过计算 C 空间中保存的引用,仅在 cpyext 层模拟引用计数。这意味着 PyPy 中的引用计数通常与 CPython 中的引用计数不同,因为它不计算 Python 空间中保存的任何引用。

作为不同垃圾收集特征的直接结果,对象可能会在 CPython 之外的其他点看到它们的生命周期结束。因此,当预期物体在 CPython 中死亡但在 PyPy 中可能没有时,必须特别小心。具体来说,扩展类型()的解除分配器方法可能会在比 CPython 更晚的时间点被调用,而是由内存变得比被死的对象更紧密地触发。

如果代码中的点在某个对象应该死亡时是已知的(例如,当它与另一个对象或某个函数的执行时间相关联时),那么值得考虑它是否可以无效并在此时手动清理而不是依赖于解除分配器。

作为副作用,这有时甚至可以导致更好的代码设计,例如,当上下文管理器可以与语句一起使用时。

PyPy 中的内存管理允许在内存中移动对象。 C-API 层只是 PyPy 对象的间接视图,通常将数据或状态复制到 C 空间,然后绑定到 C-API 对象的生命周期,而不是底层的 PyPy 对象。重要的是要理解这两个对象在 cpyext 中是不同的东西。

效果可能是当使用数据指针或借用引用,并且不再直接从 C 空间引用拥有对象时,引用或数据指针在某些时候可能变得无效,即使对象本身仍然存在。与 CPython 相反,仅仅在列表(或其他 Python 容器)中保持对对象的引用是不够的,因为它们的内容仅在 Python 空间中管理,因此仅引用 PyPy 对象。 Python 容器中的引用不会使 C-API 视图保持活动状态。 Python 类 dict 中的条目显然也不起作用。

可能发生这种情况的一个更明显的地方是访问字节字符串的缓冲区。在 PyPy 中,只有在 Cython 代码持有对字节字符串对象本身的直接引用时,这才会起作用。

另一点是当直接使用 CPython C-API 函数返回借用的引用时,例如, 和类似的函数,但也有一些函数返回对内置模块或运行时环境的低级对象的借用引用。 PyPy 中的 GIL 只保证借用的引用在下次调用 PyPy(或其 C-API)时保持有效,但不一定更长。

当访问 Python 对象的内部或使用借用的引用时间长于下一次调用 PyPy 时,包括引用计数或释放 GIL 的任何东西,因此需要在 C 空间中另外保持对这些对象的直接拥有引用,例如,在函数中的局部变量或扩展类型的属性中。

如有疑问,请避免使用返回借用引用的 C-API 函数,或者在获取引用和 时通过对 的一对调用显式包围借用引用的使用完成后将其转换为自己的引用。

以下内置类型目前在 cpyext 中不以 C 级表示形式提供: , 和。

内置类型的许多类型槽函数未在 cpyext 中初始化,因此不能直接使用。

类似地,几乎没有内置类型的(实现)特定结构域在 C 级暴露,例如 的字段或的字段。 struct 等虽然容器的字段(宏使用)可用,但不保证准确。

最好不要访问任何这些结构域和插槽,而是使用普通的 Python 类型以及对象操作的普通 Python 协议。 Cython 会将它们映射到 CPython 和 cpyext 中 C-API 的适当用法。

目前,GIL 处理函数 在 PyPy 中不可重入,并且在被调用两次时死锁。这意味着试图获取 GIL“以防万一”的代码,因为它可能在有或没有 GIL 的情况下被调用,但在 PyPy 中不会按预期工作。如果 GIL 已经持有,请参见 PyGILState_Ensure 不应该死锁。

简单的函数,尤其是用于 CPython 速度的宏,可能在 cpyext 中表现出截然不同的性能特征。

返回借用引用的函数已被提及为需要特别小心,但它们也会导致更多的运行时开销,因为它们经常在 PyPy 中创建弱引用,它们只返回 CPython 中的普通指针。可见的例子是 。

一些更高级别的功能也可能表现出完全不同的性能特征,例如, 用于 dict 迭代。虽然它是在 CPython 中迭代 dict 的最快方法,具有线性时间复杂度和低开销,但它目前在 PyPy 中具有二次运行时因为它映射到正常的 dict 迭代,它无法跟踪两个调用之间的当前位置,因此需要在每次调用时重新启动迭代。

这里的一般建议比 CPython 更适用,最好依靠 Cython 为您生成适当的 C-API 处理代码,而不是直接使用 C-API - 除非您真的知道自己在做什么。如果你发现在 PyPy 和 cpyext 中做一些比 Cython 目前做得更好的方法,最好修复 Cython 以获得每个人的好处。

  • 从 PyPy 1.9 开始,在极少数情况下,子类型内置类型会导致方法调用的无限递归。
  • 特殊方法的 Docstrings 不会传播到 Python 空间。
  • pypy3 中的 Python 3.x 改编只是慢慢开始包含 C-API,因此可以预期更多的不兼容性。

PyPy 中的 cpyext 实现比经过充分测试的 C-API 及其在 CPython 中的底层本机实现要年轻得多且不太成熟。遇到崩溃时应记住这一点,因为问题可能并不总是存在于您的代码或 Cython 中。此外,PyPy 及其 cpyext 实现在 C 级别比 CPython 和 Cython 更容易调试,仅仅因为它们不是为它而设计的。

原文: http://docs.cython.org/en/latest/src/userguide/limitations.html

此页面用于列出 Cython 中的错误,这些错误使得编译代码的语义与 Python 中的语义不同。大多数缺失的功能已在 Cython 0.15 中修复。未来的 Cython 版本计划提供完整的 Python 语言兼容性。目前,问题跟踪器可以提供我们知道并希望修复的偏差的概述。

https://github.com/cython/cython/labels/Python%20Semantics

以下是我们可能无法解决的差异列表。大多数这些事情更多地落入实现细节而不是语义,我们可能决定不修复(或需要一个-pedantic 标志来获取)。

这在 Python 3 中被删除了。

虽然很有可能在 Cython 自己的函数类型中模拟函数的接口,并且最近的 Cython 版本在这里看到了一些改进,但“inspect”模块并没有将 Cython 实现的函数视为“函数”,因为它测试了对象类型显式而不是比较抽象接口或抽象基类。这对使用 inspect 来检查函数对象的代码有负面影响,但是需要对 Python 本身进行更改。

目前,我们生成假追踪作为异常传播的一部分,但不填写本地并且无法填写 co_code。为了完全兼容,我们必须在函数调用时生成这些堆栈帧对象(具有潜在的性能损失)。我们可以选择启用此功能进行调试。

原文: http://docs.cython.org/en/latest/src/userguide/pyrex_differences.html

警告

Cython 和 Pyrex 都是移动目标。已经到了这一点,两个项目之间所有差异的明确列表将很难列出和跟踪,但希望这个高级列表能够了解存在的差异。应该注意的是,两个项目都努力相互兼容,但 Cython 的目标是尽可能接近并完成 Python 的合理性。

Cython 创建了文件,可以在 Python 2.x 和 Python 3.x 中构建和使用。实际上,使用 Cython 编译模块很可能是将代码移植到 Python 3 的简单方法。

Cython 还支持 Python 3.0 和后来的主要 Python 版本附带的各种语法添加。如果它们不与现有的 Python 2.x 语法或语义冲突,它们通常只是被编译器接受。其他一切都取决于编译器指令(参见 编译器指令 )。

Cython 支持 Python 3 为列表,集和 dicts 定义的不同理解:

如果是列表,元组或字典,则优化循环。您也可以使用 … 语法,但通常最好使用通常的 … 语法与 C 运行变量(例如)。

注意

见 自动量程转换

请注意,Cython 还支持从 Python 2.4 开始的集合文字。

Python 函数可以在参数之后和参数之前列出仅限关键字的参数,例如:

这里,和不能作为位置参数传递,必须作为关键字参数传递。此外,和是必需的关键字参数,因为它们没有默认值。

如果省略之后的参数名,则该函数将不接受任何额外的位置参数,例如:

采用两个位置参数,并有两个必需的关键字参数。

https://www.python.org/dev/peps/pep-0308/ 中描述的条件表达式:

仅评估和中的一个(取决于 C 的值)。

模块级函数现在可以内联声明, 关键字传递给 C 编译器。这些可以和宏一样快:

请注意,类级 函数是通过虚函数表处理的,因此几乎在所有情况下编译器都无法内联它们。

在 Pyrex 中,必须写:

现在,有了 cython,人们可以写:

右边的表达可以任意复杂,例如:

收益率:

Note

不鼓励使用此语法,因为它对于普通的 Python 循环来说是多余的。参见 自动量程转换 。

在 C 中,int 用于真值。在 python 中,任何对象都可以用作真值(使用方法),但规范选择是两个布尔对象和。 (用于“boolean int”)类型被编译为 C int,但是作为布尔值强制进出 Python。比较的返回类型和几个内置函数也是。这减少了在中包装物品的需要。例如,人们可以写:

它将在 Pyrex 中返回或,但在 Cython 中返回或。可以声明函数的变量和返回值为类型。例如:

第一次转换将通过进行,而第二次转换将通过(a.k.a。)进行,并对已知的内置类型进行适当的优化。

包括工作 :

Cython 在通常的 和 之上添加了第三种功能类型。如果声明了一个函数 ,它可以被扩展和普通的 python 子类调用和覆盖。您基本上可以将 方法视为 方法+一些额外的方法。 (这就是它至少实现的方式。)首先,它创建了一个 方法,除了调用底层 方法之外什么都不做(并且如果需要,可以进行参数解包/强制) )。在 方法的顶部添加了一些代码以查看它是否被覆盖,类似于以下伪代码:

要检测类型是否具有字典,它只检查插槽,对于扩展类型,它是(默认情况下),但对于实例类,则为非空。如果字典存在,它会执行单个属性查找,并且可以(通过比较指针)判断返回的结果是否实际上是新函数。如果且仅当它是一个新函数时,则参数被打包到元组和方法中。这一切都非常快。设置了一个标志,因此如果直接在类上调用方法,则不会发生此查找,例如:

有关说明和使用提示,请参阅 早期绑定速度 。

当是任何 cdef’d 整数类型时,这将把形式的语句转换为,并且可以确定方向(即步骤的符号)。

Warning

如果范围导致赋值给溢出,这可能会改变语义。具体来说,如果设置了此选项,则在输入循环之前将引发错误,而如果没有此选项,循环将执行,直到遇到溢出值。如果这会影响你,请更改(最终会有更好的方法来设置它)。

在 Pyrex 中,如果有一个类型,其中是一个 Python 对象,那么将获得的内存地址。同样,如果一个类型,其中是一个 C int,那么将在内存中的位置获得一个“对象”。这会导致混乱的结果和段错误。

在 Cython 中,如果其中一个类型是 python 对象,则会尝试强制执行(如将赋值给类型类型的变量时)。它不会阻止一个没有转换的地方(虽然它会发出警告)。如果一个人真的想要这个地址,首先要转换为。

如在 Pyrex 中将转换为类型而不进行任何类型检查。 Cython 支持使用类型检查进行转换的语法(即如果不是的子类,它将抛出错误。

Cython 现在支持 和 功能的可选参数。

文件中的语法保留在 Python 中,但是通过写在文件中声明了这些函数。子类化时参数的数量可能会增加,但参数类型和顺序必须保持不变。在某些情况下,如果没有任何可选项的 cdef / cpdef 函数被一个具有默认参数值的函数覆盖,则会有轻微的性能损失。

例如,可以有文件:

使用相应的文件:

Note

这也证明了 功能如何覆盖 功能。

为方便起见, 中声明的函数会自动转换为函数指针。

函数现在可以声明为:

在这种情况下,捕获 C ++错误时将引发 Python 异常。有关详细信息,请参阅 在 Cython中使用 C ++。

与的含义相同

Cython 支持 PEP 3120PEP 263 ,即你可以开始你的 Cython 带有编码注释的源文件,通常用 UTF-8 编写源代码。这会影响字节字符串的编码以及将等 unicode 字符串文字转换为 unicode 对象。

而不是像 Pyrex 文档中所解释的那样引入新关键字,只要 与扩展类型一起使用,Cython 就会发出(非欺骗性和更快速)的类型检查第二个参数。

Cython 支持多种指令,即,,和。

始终启用语句。

Cython 支持编译文件,并使用装饰器和其他有效的 Python 语法接受类型注释。这允许将相同的源解释为直接 Python,或者编译以获得优化结果。有关详细信息,请参阅 纯 Python 模式 。

原文: http://docs.cython.org/en/latest/src/userguide/memoryviews.html

类型化的内存视图允许有效访问内存缓冲区,例如 NumPy 阵列的内存缓冲区,而不会产生任何 Python 开销。 Memoryview 类似于当前的 NumPy 阵列缓冲支持(),但它们具有更多功能和更清晰的语法。

Memoryview 比旧的 NumPy 阵列缓冲支持更通用,因为它们可以处理更多种类的数据源。例如,它们可以处理 C 数组和 Cython 数组类型( Cython 数组 )。

memoryview 可以在任何上下文中使用(函数参数,模块级,cdef 类属性等),并且几乎可以通过 PEP 3118 缓冲区接口从任何暴露可写缓冲区的对象中获取。

如果您习惯使用 NumPy,以下示例将使您开始使用 Cython 内存视图。

此代码应提供以下输出:

内存视图以与 NumPy 类似的方式使用 Python 切片语法。

要在一维 int 缓冲区上创建完整视图:

完整的 3D 视图:

它们也可以方便地作为函数参数:

参数的声明自动拒绝 None 值作为输入,否则将允许。默认情况下允许 None 的原因是它可以方便地用于返回参数:

Cython 将自动拒绝不兼容的缓冲区,例如将三维缓冲区传递给需要二维缓冲区的函数会产生。

在 Cython 中,内存视图上的索引访问会自动转换为内存地址。以下代码请求 C 类型的项目和索引的二维内存视图:

负指数也起作用,从相应维度的末尾开始计算:

以下函数循环遍历 2D 数组的每个维度,并为每个项目添加 1:

索引和切片可以在有或没有 GIL 的情况下完成。它基本上像 NumPy 一样工作。如果为每个维度指定了索引,您将获得基本类型的元素(例如 <cite>int</cite> )。否则,您将获得一个新视图。省略号表示您为每个未指定的维度获取连续切片:

内存视图可以复制到位:

也可以使用和方法复制它们;见 C 和 Fortran 连续拷贝 。

在大多数情况下(见下文),内存视图的转置方式与 NumPy 切片可以转置的方式相同:

这为数据提供了一个新的转置视图。

转置要求存储器视图的所有维度都具有直接存取存储器布局(即,没有通过指针的间接指令)。有关详细信息,请参阅 指定更一般的存储器布局 。

对于 NumPy,可以通过使用索引数组来引入新轴

可以将新的轴索引与所有其他形式的索引和切片混合。另见示例。

从 Cython 0.28 开始,memoryview 项类型可以声明为以支持只读缓冲区作为输入:

使用带有二进制 Python 字符串的非 const 内存视图会产生运行时错误。您可以使用内存视图解决此问题:

注意,这不是 要求 输入缓冲区是只读的:

视图仍然接受可写缓冲区,但非 const,可写视图不接受只读缓冲区:

您可能更喜欢使用旧视图的内存视图,因为:

  • 语法更清晰
  • Memoryview 通常不需要 GIL(参见 Memoryviews 和 GIL)
  • 记忆视图要快得多

例如,这是上面函数的旧语法等价物:

请注意,我们不能像上面的 memoryview 版本那样使用作为函数的缓冲版本,因为缓冲区对象是 Python 对象。但是,即使我们不将与 memoryview 一起使用,它也要快得多。这是导入两个版本后 IPython 会话的输出:

Cython 内存视图几乎支持导出 Python 新样式缓冲区接口的所有对象。这是 PEP 3118 中描述的缓冲接口。 NumPy 数组支持此接口, Cython 数组 也是如此。 “几乎所有”是因为 Python 缓冲区接口允许数据数组中的 元素 本身成为指针; Cython 的内存视图还不支持这一点。

缓冲区接口允许对象以各种方式识别底层内存。除了数据元素的指针外,Cython 内存视图支持所有 Python 新型缓冲区布局。如果内存必须是外部例程的特定格式或代码优化,则了解或指定内存布局可能很有用。

概念如下:有数据访问和数据打包。数据访问意味着直接(无指针)或间接(指针)。数据打包意味着您的数据在内存中可能是连续的或不连续的,并且可以使用 步幅 来识别连续索引需要为每个维度进行的内存跳转。

NumPy 数组提供了一个良好的跨步直接数据访问模型,因此我们将使用它们来更新 C 和 Fortran 连续数组的概念以及数据步幅。

最简单的数据布局可能是 C 连续数组。这是 NumPy 和 Cython 数组中的默认布局。 C 连续意味着阵列数据在存储器中是连续的(见下文),并且阵列的第一维中的相邻元素在存储器中是最远的,而最后维中的相邻元素最接近在一起。例如,在 NumPy 中:

这里,和在存储器中相隔一个字节,而和相距 3 个字节。这引出了我们 步幅 的想法。数组的每个轴都有一个步长,这是从该轴上的一个元素到下一个元素所需的字节数。在上面的例子中,轴 0 和 1 的步幅显然是:

对于 3D C 连续数组:

Fortran 连续数组具有相反的内存排序,第一个轴上的元素在内存中最接近:

连续数组是单个连续存储器块包含数组元素的所有数据的数组,因此存储器块长度是数组中元素数量和元素大小(以字节为单位)的乘积。在上面的示例中,内存块长度为 2 3 4 * 1 个字节,其中 1 是 int8 的长度。

数组可以是连续的而不是 C 或 Fortran 顺序:

切片 NumPy 数组很容易使它不连续:

正如您在 中看到的那样,指定更一般的内存布局 ,您可以为内存视图的任何维度指定内存布局。对于未指定布局的任何维度,假定数据访问是直接的,并假设数据打包是跨越的。例如,这将是内存视图的假设,如:

您可以使用定义中的步骤语法为内存视图指定 C 和 Fortran 连续布局。例如,如果您确定您的内存视图将位于 3D C 连续布局之上,您可以编写:

其中可以是 C 连续的 NumPy 数组。第 3 位的意味着该第 3 维中的元素将是存储器中的一个元素。如果您知道将拥有 3D Fortran 连续数组:

例如,如果传递非连续缓冲区

你会在运行时得到:

因此,切片类型规范中的 <cite>:: 1</cite> 指示数据在哪个维度上是连续的。它只能用于指定完整的 C 或 Fortran 连续性。

可以使用和方法使 C 或 Fortran 连续复制:

可以使用先前看到的切片语法或使用中的任何常量指定数据布局。如果在任何维度中都没有给出说明符,则假定数据访问是直接的,并假设数据打包是跨步的。如果你不知道维度是直接的还是间接的(因为你可能从某个库得到一个带缓冲接口的对象),那么你可以指定<cite>泛型</cite>标志,在这种情况下它将在运行时确定。

标志如下:

  • 通用 - 跨步,直接或间接
  • 跨步 - 跨步(直接)(这是默认值)
  • 间接 - 跨步和间接的
  • 连续的 - 连续的和直接的
  • indirect_contiguous - 指针列表是连续的

它们可以像这样使用:

只有间接维度后面的第一个,最后一个或维度可以指定为连续的:

<cite>连续</cite>标志和 <cite>:: 1</cite> 说明符之间的区别在于前者仅指定一个维度的邻接,而后者指定所有后续(Fortran)或前一个(C)的邻接。 )尺寸:

前一种情况是有效的,因为最后一个维度仍然是连续的,但是第一个维度不再“跟随”最后一个维度(意思是,它已经跨越了,但它不再是 C 或 Fortran 连续),因为它被切成了。

正如您将从 快速入门 部分中看到的那样,内存视图通常不需要 GIL:

特别是,您不需要 GIL 进行内存视图索引,切片或转置。 Memoryviews 需要 GIL 用于复制方法( C 和 Fortran 连续拷贝 ),或者当 dtype 是对象并且读取或写入对象元素时。

这些类型化的内存视图可以转换为 Python 内存视图对象( <cite>cython.view.memoryview</cite> )。这些 Python 对象可以像原始内存视图一样进行索引,可切片和转换。它们也可以随时转换回 Cython 空间的内存视图。

它们具有以下属性:

  • :每个维度的大小,作为元组。
  • :沿每个维度跨步,以字节为单位。
  • :维数。
  • :视图中的项目总数(形状的乘积)。
  • :视图中项目的大小(以字节为单位)。
  • :等于乘以。

当然还有前面提到的属性( Transposing)。这些属性与 NumPy 具有相同的语义。例如,要检索原始对象:

请注意,此示例返回从中获取视图的原始对象,并在此期间重新查看视图。

每当复制 Cython 内存视图时(使用任何<cite>副本</cite>或 <cite>copy_fortran</cite> 方法),您将获得新创建的对象的新内存视图片段。此数组也可以手动使用,并自动分配数据块。稍后可以将其分配给 C 或 Fortran 连续切片(或跨步切片)。它可以像:

它还需要一个可选参数<cite>模式</cite>(’c’或’fortran’)和一个布尔 <cite>allocate_buffer</cite> ,它指示缓冲区是否应该在超出范围时分配和释放:

您还可以将指针转换为数组,或将 C 数组转换为数组:

当然,您也可以立即将 cython.view.array 分配给类型化的 memoryview 切片。可以将 C 数组直接分配给 memoryview 切片:

这些数组可以像 Python 内存对象一样从 Python 空间进行索引和切片,并且具有与 memoryview 对象相同的属性。

的替代方案是 Python 标准库中的模块。在 Python 3 中,类型本身支持缓冲区接口,因此内存视图无需额外设置即可在其上工作。

但是,从 Cython 0.17 开始,可以在 Python 2 中使用这些数组作为缓冲提供程序。这是通过显式 cimporting 模块完成的,如下所示:

请注意,cimport 还为数组类型启用旧的缓冲区语法。因此,以下也有效:

Memoryview(和数组)对象可以强制转换为 NumPy ndarray,而无需复制数据。你可以,例如做:

当然,您不限于使用 NumPy 的类型(例如此处的),您可以使用任何可用的类型。

尽管 memoryview 切片不是对象,但它们可以设置为 None,并且可以检查它们是否为 None:

如果函数需要实内存视图作为输入,则最好在签名中直接拒绝 None 输入,这在 Cython 0.17 及更高版本中受支持,如下所示:

与扩展类的对象属性不同,memoryview 切片不会初始化为 None。

由于在 C 中使用指针是无处不在的,这里我们给出一个快速示例,说明如何调用其参数包含指针的 C 函数。假设您想要使用 NumPy 管理数组(分配和释放)(它也可以是 Python 数组,或者任何支持缓冲区接口的数组),但是您希望使用中实现的外部 C 函数对此数组执行计算]:

|

|

|

此文件附带一个名为的头文件,其中包含:

|

|

|

其中指向数组,是其大小。

您可以通过以下方式在 Cython 文件中调用该函数:

|

|

|

Several things to note:

  • 请求 C 连续视图,如果缓冲区不是 C 连续则失败。参见 C 和 Fortran 连续记忆视图 。
  • 可以理解为’存储器视图的第一个元素的地址’。对于连续数组,这相当于平坦内存缓冲区的起始地址。
  • 可能被,或取代。但更有效,因为它不需要任何 Python 交互。
  • 如果传递的数组是连续的,将就地执行计算,如果不连续,它将返回一个新的 numpy 数组。
  • 如果您使用的是 Python 数组而不是 numpy 数组,则无需检查数据是否连续存储,因为总是如此。参见 使用 Python 数组 。

这样,您可以调用类似于普通 Python 函数的 C 函数,并将所有内存管理和清理留给 NumPy 数组和 Python 的对象处理。有关如何在 C 文件中编译和调用函数的详细信息,请参阅 使用 C 库 。

原文: http://docs.cython.org/en/latest/src/userguide/buffer.html

Cython 对象可以通过实现“缓冲协议”将内存缓冲区暴露给 Python 代码。本章介绍如何实现协议并使用 NumPy 中扩展类型管理的内存。

以下 Cython / C ++代码实现了一个浮点矩阵,其中列数在构造时固定,但行可以动态添加。

没有方法可以用矩阵的内容做任何有效的工作。我们可以为此实现自定义,等,但我们将使用缓冲协议将矩阵的数据暴露给 Python,这样我们就可以使用 NumPy 来完成有用的工作。

实现缓冲协议需要添加两个方法,和,Cython 专门处理。

方法填充由 Python C-API 定义的称为的描述符结构。它包含指向内存中实际缓冲区的指针,以及有关数组形状和步幅的元数据(从一个元素或行到下一个元素或行的步长)。它的和成员是必须指向类型和大小的数组的指针。只要任何缓冲区查看数据,这些数组就必须保持活动状态,因此我们将它们作为成员存储在对象上。

代码尚未完成,但我们已经可以编译它并测试基本功能。

现在我们可以将视为 NumPy ,并使用标准的 NumPy 操作修改其内容。

到目前为止实施的类是不安全的。 操作可以移动底层缓冲区,这会使数据上的任何 NumPy(或其他)视图无效。如果您尝试在调用后访问值,您将获得过时的值或段错误。

这就是的用武之地。我们可以为每个矩阵添加一个引用计数,并在视图存在时锁定它以进行变异。

我们在代码中跳过了一些输入验证。 的参数来自(和其他客户端),是一个描述所请求数组类型的布尔标志的 OR。严格地说,如果标志包含,或,必须提高。这些宏可以是的 .d。

(矢量矩阵结构实际上符合,但这会阻止填充步幅。单行矩阵是 F-连续的,但是更大的矩阵不是。)

这里使用的缓冲接口在 PEP 3118 中列出,修改缓冲液方案。

有关使用 C 语言的教程,请参阅 Jake Vanderplas 的博客 Python 缓冲协议简介。

参考文档可用于 Python 3 和 Python 2 。 Py2 文档还描述了一个不再使用的旧缓冲区协议;自 Python 2.6 起, PEP 3118 协议已经实现,旧协议仅与遗留代码相关。

原文: http://docs.cython.org/en/latest/src/userguide/parallelism.html

Cython 通过 模块支持原生并行性。要使用这种并行性,必须释放 GIL(参见 释放 GIL)。它目前支持 OpenMP,但稍后可能会支持更多后端。

注意

由于 OpenMP 限制,此模块中的功能仅可用于主线程或并行区域。

([start,] stop[, step][, nogil=False][, schedule=None[, chunksize=None]][, num_threads=None])

此函数可用于并行循环。 OpenMP 自动启动线程池并根据使用的计划分配工作。

线程局部性和减少量是自动推断的变量。

如果分配给 prange 块中的变量,它将变为 lastprivate,这意味着变量将包含上次迭代的值。如果对变量使用 inplace 运算符,它将变为减少,这意味着变量的线程局部副本的值将随操作符一起减少,并在循环后分配给原始变量。索引变量始终是 lastprivate。与块并行分配的变量在块之后将是私有的并且不可用,因为没有顺序最后值的概念。

<colgroup><col class=”field-name”> <col class=”field-body”></colgroup>| 参数: |

  • start - 指示循环开始的索引(与范围中的起始参数相同)。
  • stop - 指示何时停止循环的索引(与范围中的停止参数相同)。
  • - 给出序列步骤的整数(与范围中的步骤参数相同)。它不能为 0。
  • nogil - 此功能只能与发布的 GIL 一起使用。如果为真,则循环将包裹在 nogil 部分中。
  • schedule

    传递给 OpenMP,可以是以下之一:

    static:

    If a chunksize is provided, iterations are distributed to all threads ahead of time in blocks of the given chunksize. If no chunksize is given, the iteration space is divided into chunks that are approximately equal in size, and at most one chunk is assigned to each thread in advance.

    当调度开销很重要并且可以将问题简化为已知具有大致相同运行时的相同大小的块时,这是最合适的。

    dynamic:

    The iterations are distributed to threads as they request them, with a default chunk size of 1.

    当每个块的运行时间不同并且事先不知道时,这是合适的,因此使用更多数量的较小块来保持所有线程忙。

    guided:

    As with dynamic scheduling, the iterations are distributed to threads as they request them, but with decreasing chunk size. The size of each chunk is proportional to the number of unassigned iterations divided by the number of participating threads, decreasing to 1 (or the chunksize if provided).

    这比纯动态调度有一个优势,当事实证明最后一个块比预期花费更多时间或者其他方式被错误调度时,所以大多数线程开始运行空闲而最后一个块只由较少数量的线程处理。

    runtime:

    The schedule and chunk size are taken from the runtime scheduling variable, which can be set through the function call, or the OMP_SCHEDULE environment variable. Note that this essentially disables any static compile time optimisations of the scheduling code itself and may therefore show a slightly worse performance than when the same scheduling policy is statically configured at compile time. The default schedule is implementation defined. For more information consult the OpenMP specification [1].

  • num_threads - 参数表示团队应该包含多少个线程。如果没有给出,OpenMP 将决定使用多少线程。通常,这是计算机上可用的核心数。但是,这可以通过功能或环境变量来控制。
  • chunksize - 参数指示用于在线程之间划分迭代的块大小。这仅对,和调度有效,并且是可选的。根据日程安排,它提供的负载平衡,调度开销和错误共享的数量(如果有的话),不同的组块可以提供显着不同的性能结果。

    || —- | —- |

减少的例子:

带有类型化内存视图的示例(例如 NumPy 数组):

(num_threads=None)

该指令可用作语句的一部分,以并行执行代码序列。这对于设置 prange 使用的线程局部缓冲区非常有用。包含的 prange 将是一个不平行的工作共享循环,因此在并行部分中分配给的任何变量对于 prange 也是私有的。在并行块之后,并行块中的私有变量不可用。

线程局部缓冲区的示例:

稍后可能会在并行块中支持部分,以在线程之间分配工作的代码部分。

()

返回线程的 id。对于 n 个线程,id 的范围从 0 到 n-1。

要实际使用 OpenMP 支持,您需要告诉 C 或 C ++编译器启用 OpenMP。对于 gcc,这可以在 setup.py 中完成如下:

对于 Microsoft Visual C ++编译器,请使用而不是。

并行和 prange 块支持语句中断,继续并以 nogil 模式返回。此外,在这些块中使用块是有效的,并且具有从它们传播的异常。但是,因为块使用 OpenMP,所以不能只留下它们,因此现有的过程是最好的努力。对于 prange(),这意味着在任何线程中的任何后续迭代的第一次中断,返回或异常之后跳过循环体。如果可能返回多个不同的值,则返回哪个值是未定义的,因为迭代没有特定的顺序:

在上面的例子中,未定义是否应该引发异常,它是否会简单地中断或者它是否会返回 2。

可以通过 cimporting 使用 OpenMP 函数:

参考

| [1] | https://www.openmp.org/mp-documents/spec30.pdf |

  • 上一篇: jwt依赖包
  • 下一篇: 组策略 win10家庭版
  • 版权声明


    相关文章:

  • jwt依赖包2025-01-04 11:01:04
  • 批处理运行cmd命令2025-01-04 11:01:04
  • 安装程序错误代码25022025-01-04 11:01:04
  • java orm框架性能比较2025-01-04 11:01:04
  • 2021免费dns2025-01-04 11:01:04
  • 组策略 win10家庭版2025-01-04 11:01:04
  • 归并排序例题讲解2025-01-04 11:01:04
  • 看上去好坑的运算符重载2025-01-04 11:01:04
  • 二叉排序树规则2025-01-04 11:01:04
  • 异或和怎么算2025-01-04 11:01:04