python - 在 Python C 扩展中使用来自 PyObjects 的数据而不持有 GIL
问题描述
在我的 Python C 扩展中,我正在对字符串的可迭代执行操作。因此,在第一步中,我调用PySequence_Fast
将其转换为列表,然后遍历元素。对于我使用的每个字符串PyUnicode_DATA
,然后使用一些标准比较字符串。所以我只从 PyObjects 中读取,但从不修改它们。
现在我想并行处理列表,这需要我释放 GIL。但是我不知道这对我的用例有什么影响。以下是我目前的想法:
我仍然可以使用这些 API,因为它们只是宏,可以直接从 PyObjects 读取而不修改它们。
我必须事先使用 API 并存储一个包含
kind
,length
和data pointer
字符串的结构数组我必须事先使用 API,并且必须将字符串的副本存储在数组中
案例 1 将是性能和内存效率最高的。但是,如果没有获得 GIL,则不允许在 Python 对象上执行(这是否包括读取权限)或使用 Python/C API 函数。
案例 2 将是下一个最有效的,因为至少我不必复制所有字符串。但是,当我在 GIL 发布时不允许从 Python 对象中读取数据时,我想知道是否允许我使用指向 PyObject 内部数据的指针。
案例 3 将要求我复制所有字符串。就我而言,这可能会使多线程解决方案比顺序解决方案慢。
我希望有人能帮助我了解在 GIL 发布期间我可以做什么。
解决方案
我认为官方的回答是你不应该使用方法 1,而应该使用方法 2 和 3。虽然它现在可能有效,但将来可能会发生变化并中断。如果您想支持 PyPy 的 C-API 包装器(它可能在内部使用与 Python 不同的表示形式),这一点尤其重要。有越来越多的举措试图隐藏您可能会被抓住的实施细节。
实际上,我认为方法 1 可以正常工作,前提是您只使用没有错误检查的宏形式 - GIL 主要是关于停止同时写入将 Python 对象置于未定义状态,而您没有这样做。我会稍微小心的是,如果您曾经拥有(已弃用)“非规范”unicode 对象 - 看起来像“macro-y”的东西PyUnicode_READY
可能会导致它们被修改为规范状态。同样,要特别警惕 C-API 的替代(非 CPython)实现。
要考虑的一种替代方法是使用缓冲区协议。虽然我在文档中找不到明确说明,但想法是需要 GIL PyObject_GetBuffer
,PyBuffer_Release
但读/写缓冲区不需要。这里我有两个子建议:
- 你能有一个像 Numpy 数组这样的单个对象,它将所有字符串作为缓冲区公开吗?
- 您还可以从 unicode 对象(作为 utf-8 C 字符串)获取缓冲区 - 要做的事情是使用 GIL 创建所有缓冲区,在没有的情况下进行并行处理,然后使用 GIL 释放它们。这样做的开销可能是低效的。这基本上是方法 2 的“官方”版本。
我简短地说,你可能会侥幸逃脱,但如果它打破了,我怀疑向 Python 提交的错误报告是否会受到好评(因为它在技术上是错误的)
推荐阅读
- android - 在 Windows 或 Ubuntu 中为 Android 构建 libcurl
- apache-spark - 如何在没有数据框的火花中执行列表达式
- oracle - Oracle:你能专门授予 CREATE GLOBAL TEMPORARY TABLE 吗?
- angular - Angular HttpClient Subscription ...没有返回数据?
- android - 如何打开图库并从适配器类中选择图像?
- c++ - 涉及 CRTP 和内部类型的类专业化
- azure - AADB2C 遵循 Salesforce 自定义策略指南
- laravel - 用于资源文件 (CSS/JS) 的 Laravel React-router 404
- javascript - 多个输入框 - alertifyjs / Jquery
- qt - ListView 中的矩形