我有一些 Cython 代码,我想尽快运行。我需要释放 GIL 才能执行此操作吗?
假设我的代码与此类似:
import numpy as np
# trivial definition just for illustration!
cdef double some_complicated_function(double x) nogil:
return x
cdef void func(double[:] input) nogil:
cdef double[:] array = np.zeros_like(input)
for i in range(array.shape[0]):
array[i] = some_complicated_function(input[i])
我收到了一大堆错误消息np.zeros_like
行类似于:
nogilcode.pyx:7:40: Calling gil-requiring function not allowed without gil
nogilcode.pyx:7:29: Accessing Python attribute not allowed without gil
nogilcode.pyx:7:27: Accessing Python global or builtin not allowed without gil
nogilcode.pyx:7:40: Constructing Python tuple not allowed without gil
nogilcode.pyx:7:41: Converting to Python object not allowed without gil
我需要找到一种调用方式吗np.zeros_like
没有GIL?或者找到其他不需要 GIL 的分配数组的方法?
注意:这是一个自我回答的问题,旨在消除有关 Cython 和 GIL 的一些常见误解(当然,也欢迎您回答它!)。
第二个注意事项:我已经为 Cython 做出了足够的贡献,因此我应该在这里注明(鉴于我正在提出这个主题)
No-你可能不知道need释放 GIL。
GIL(全局解释器锁)的基本功能是通过确保一次只有一个Python线程能够运行来确保Python的内部机制不受竞争条件的影响。然而,仅仅保留 GIL 并不会减慢你的代码速度。
您应该释放 GIL 的两个(相关)场合是:
-
Using Cython的并行机制 https://cython.readthedocs.io/en/latest/src/userguide/parallelism.html。的内容prange
例如循环需要是nogil
.
-
如果您希望其他(外部)Python 线程能够同时运行。
A。如果您有一个不需要 GIL 的大型计算/IO 密集型块,那么释放它可能是“礼貌”的做法,只是为了让想要执行多线程的代码用户受益。然而,这主要是有用的而不是必要的。
b. (非常非常偶尔)有时用短命令短暂释放 GIL 很有用with nogil: pass
堵塞。这是因为 Cython 不会自发释放它(与 Python 不同),因此如果您正在等待另一个 Python 线程完成任务,这可以避免死锁。除非您使用 Cython 编译 GUI 代码,否则此子点可能不适用于您。
可以在没有 GIL 的情况下运行的 Cython 代码(不调用 Python,纯 C 级数字运算)是often高效运行的代码类型。有时这会给人这样的印象:相反的情况是正确的,技巧是释放 GIL,而不是他们正在运行的实际代码。不要被这个误导——无论有没有 GIL,你的(单线程)代码都会以相同的速度运行。
因此,如果您有一个很好的快速 Numpy 函数,它可以在大数据块上快速完成您想要的操作,但只能使用 GIL 调用,那么只需调用它即可 - 没有什么坏处!
最后一点:即使在nogil
块(例如prange
循环),如果需要,您可以随时取回 GIL:
with gil:
... # small block of GIL requiring code goes here
尽量不要太频繁地执行此操作(获取/释放它需要时间,当然,一次只能有一个线程运行此块),但同样,这是在需要时执行小型 Python 操作的一种好方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)