我有一些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
我是否需要找到一种不使用GIL调用np.zeros_like
的方法?或者找到其他方法来分配不需要GIL的数组
注意:这是一个自我回答的问题,旨在澄清一些关于Cython和GIL的常见误解(当然,欢迎您也回答!)
否-您可能不需要释放GIL
GIL(全局解释器锁)的基本功能是确保一次只能运行一个Python线程,从而确保Python的内部机制不受竞争条件的影响。然而,仅仅持有GIL并不会降低代码的速度
应发布GIL的两种(相关)情况是:
使用Cython's parallelism mechanism。例如
prange
循环的内容必须是nogil
如果希望其他(外部)Python线程能够同时运行
a。如果您有一个不需要GIL的大型计算/IO密集型块,那么释放它可能是“礼貌的”,只是为了让希望执行多线程的代码用户受益。然而,这主要是有用的,而不是必要的
b。(非常,非常偶尔)有时用一个短的
with nogil: pass
块短暂地释放GIL是有用的。这是因为Cython不会自动释放它(与Python不同),所以如果您正在等待另一个Python线程完成任务,这可以避免死锁。除非您使用Cython编译GUI代码,否则此子点可能不适用于您可以在没有GIL的情况下运行的Cython代码(不调用Python,纯C级数值操作)通常是高效运行的代码。这有时给人的印象是相反的,诀窍是释放GIL,而不是他们正在运行的实际代码。不要被这一点误导——无论是否使用GIL,您的(单线程)代码都将以相同的速度运行
因此,如果您有一个很好的fast Numpy函数,它可以在一大块数据上快速执行您想要的操作,但只能使用GIL调用,那么只需调用它即可-不会造成任何伤害
最后一点:即使在
nogil
块(例如prange
循环)内,如果需要GIL,也可以随时将其取回:尽量不要经常这样做(获取/释放它需要时间,当然一次只能有一个线程运行此块),但同样,这也是在需要时执行小型Python操作的好方法
相关问题 更多 >
编程相关推荐