Python 我需要在Cython中使用'nogil'吗

Python 我需要在Cython中使用'nogil'吗,python,cython,gil,Python,Cython,Gil,我有一些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 = n

我有一些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.zero\u类似的
行中获得了大量错误消息,类似于:

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.zero\u的方法吗?或者找到其他方法来分配不需要GIL的数组



注意:这是一个自我回答的问题,旨在澄清一些关于Cython和GIL的常见误解(当然,欢迎您也回答!)

-您可能不需要发布GIL

GIL(全局解释器锁)的基本功能是确保一次只能运行一个Python线程,从而确保Python的内部机制不受竞争条件的影响。然而,仅仅持有GIL并不会降低代码的速度

应发布GIL的两种(相关)情况是:

  • 使用。例如,
    prange
    循环的内容必须是
    nogil

  • 如果希望其他(外部)Python线程能够同时运行

    a。如果您有一个不需要GIL的大型计算/IO密集型块,那么释放它可能是“礼貌的”,只是为了让希望执行多线程的代码用户受益。然而,这主要是有用的,而不是必要的

    b。(非常,非常偶尔)有时使用nogil:pass
  • 块短时间
    释放GIL是有用的。这是因为Cython不会自动释放它(与Python不同),所以如果您正在等待另一个Python线程完成任务,这可以避免死锁。除非您使用Cython编译GUI代码,否则此子点可能不适用于您



    可以在没有GIL的情况下运行的Cython代码(不调用Python,纯C级数值操作)通常是高效运行的代码。这有时给人的印象是相反的,诀窍是释放GIL,而不是他们正在运行的实际代码。不要被这一点误导——无论是否使用GIL,您的(单线程)代码都将以相同的速度运行

    因此,如果您有一个很好的fast Numpy函数,它可以在一大块数据上快速执行您想要的操作,但只能使用GIL调用,那么只需调用它即可-不会造成任何伤害


    最后一点:即使在
    nogil
    块(例如
    prange
    循环)内,如果需要GIL,也可以随时取回它:

    with gil:
        ... # small block of GIL requiring code goes here
    

    尽量不要经常这样做(获取/释放它需要时间,当然一次只能有一个线程运行此块)但同样,这也是在需要时执行小型Python操作的一种好方法。

    与使Python调用像
    zero一样
    相比,您可以使用cython提供的numpy的C-API来获得适度的速度。因为您填充了每个值,所以您可以使
    空的
    数组而不是
    zero
    数组。很好的一点,这可能会有所帮助。我应该说,这个问题更多的是关于nogil在Cython中什么时候是有益的,而不是像np.zero那样的。很多人似乎都是从这样一个前提开始的,即一切都必须是
    nogil
    ,而没有真正的理由,我想写一个好的答案来参考。“这有时会给人一种印象,那就是反过来是真的,诀窍是释放GIL,而不是他们正在运行的实际代码。”你对这种说法有多大信心?我记得我实现了树结构,在某些时候,在最基本的函数调用中使用“nogil”(而不是其他)显著加快了我的代码速度,而我的代码不是并行的或线程化的。已经有一段时间了,所以我可能是错的。@Oli我正在努力思考一种机制,在这种机制中,它可以产生很大的不同,所以“相当自信”。然而,我以前就错了!如果你有反例,我很想看看