【发布时间】: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:您应该将其作为答案,而不仅仅是评论!