【问题标题】:Do Python C Extensions release the GIL for CPU tasks as they do for IO tasks?Python C 扩展是否像为 IO 任务一样为 CPU 任务发布 GIL?
【发布时间】:2019-08-24 16:15:29
【问题描述】:

在进行 IO 系统调用时,Python C 扩展总是通过 Py_BEGIN_ALLOW_THREADS 释放 GIL。我已经阅读了关于 C 扩展是否为相对长时间运行的 CPU 密集型任务发布 GIL 的不同意见。我读过python解释器内的CPU受GIL约束,但C扩展内的CPU经常释放GIL。我认为这样做是安全和高效的,只要 CPU 任务可以在具有细粒度锁定的临时变量中执行,并且在对共享结构进行更新之前获取 GIL。

我在 Github 的 3.6 C 代码中搜索了Py_BEGIN_ALLOW_THREADS 的所有实例。我可能错过了一些,但在我看来,Python C 扩展通常不会为 CPU 绑定任务发布 GIL。

Python C 扩展通常会像为 IO 任务一样为 CPU 任务发布 GIL 吗?


这是我看到的唯一一个他们为 CPU 任务释放 GIL 的示例:

_hashlib.h 有一个宏 ENTER_HASHLIB,其中有一条注释表明它将在 CPU 消耗的 hashlib 操作周围释放 GIL。

sha3module.c 似乎允许在 CPU 操作之前使用线程。

_lzmamodule.c 似乎在 CPU 操作之前允许线程。


我找不到任何其他释放 GIL 的 CPU 调用(我肯定错过了一些,如果我错过了,请告诉我)。

例如:

_bisectmoduel.c 没有 Py_BEGIN_ALLOW_THREADS。

_heapqmodule.c 没有 Py_BEGIN_ALLOW_THREADS。

_json.c 没有 Py_BEGIN_ALLOW_THREADS。

_csv.c 没有 Py_BEGIN_ALLOW_THREADS。

【问题讨论】:

  • 随着 GIL 的发布,扩展模块无法安全地访问 Python 对象,因为这将允许另一个线程从它下面更改这些对象。例如,json 模块基本上除了读取或创建 Python 对象之外什么都不做,没有时间可以释放 GIL 的时间足够长。另一方面,hashlib 主要只是从不可变的str/bytes 对象中读取,其他线程无法干预。
  • @jasonharper:您应该将其作为答案,而不仅仅是评论!

标签: python-3.x python-c-api


【解决方案1】:

好吧,numpy 做到了,尽管他们将自己的宏包装在它周围 (NPY_BEGIN_ALLOW_THREADS / NPY_END_ALLOW_THREADS)

根据docs

该组用于调用可能需要一些时间但不使用任何 Python C-API 调用的代码。因此,GIL 应该在计算过程中被释放。

所以你可以释放 GIL,但只有在你不使用任何 Python C-API 调用的情况下。另一种说法是如果你不访问 Python 对象

但是您链接的最后四个扩展模块中的代码填充了 C-API 调用。因此,在那些不涉及 C-API 调用的模块中,在 C 中可能没有完成足够的计算,因此释放和重新获取 GIL 是值得的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-05
    • 1970-01-01
    • 2019-01-26
    • 2020-11-01
    • 1970-01-01
    • 2015-05-30
    相关资源
    最近更新 更多