【问题标题】:Coercion from Python not allowed without the GIL没有 GIL 就不允许来自 Python 的强制
【发布时间】:2020-04-27 05:31:31
【问题描述】:

我正在尝试从这样定义的 C++ 库中调用一个函数:

int somefunc(float timeout);

我将pxd 文件中的定义翻了一番:

int somefunc(float timeout) nogil;

但是在对pyx 文件进行 cythonizing 时,任何使用 nogil 调用函数的尝试都会导致相同的错误:

 timeout = 1.0
 with nogil:
     Q.somefunc(timeout)
Error compiling Cython file:
------------------------------------------------------------
...
            int(block), timeout,
        )

        timeout = 1.0
        with nogil:
            Q.somefunc(timeout)
                      ^
------------------------------------------------------------

script.pyx:105:23: Coercion from Python not allowed without the GIL

我也尝试使用 ctype 调用它,这会导致同样的错误。

timeout = ctypes.c_float(1.0)
with nogil:
    Q.somefunc(timeout)

仅使用浮点文字有效。使用实际 Python 变量调用此函数的正确方法是什么?

【问题讨论】:

    标签: python cython gil


    【解决方案1】:

    当你查看生成的代码时

    timeout = 1.0
    Q.somefunc(timeout)
    

    你会看到,timeoutPyObject__pyx_PyFloat_AsFloat 被调用来转换为 cdef-float。然而,在此转换过程中可能会引发异常,为此需要 gil - 因此会出现错误消息。

    解决方案是在 nogil-block 之前强制强制转换为 float

    cdef float timeout = 1.0
    with nogil:
        Q.somefunc(timeout)
    

    现在 timeout 已经是 cdef-float 并且 nogil-block 中不需要转换。


    有点不相关:我看不到代码以及Q 是什么,但大多数时候在让 C/C++ 代码完成工作时释放 gil 是错误的:

    1. 当 C/C++ 使用 openMP 进行并行化时,持有/不持有 GIL 不会改变 C/C++ 代码的任何内容(示例:https://stackoverflow.com/a/60012137/5769463)。

    2. 当线程不持有 GIL 时,其他线程可能会破坏 C/C++ 代码工作所需的对象(如 Q 或其他数据)

    3. 当处理实现缓冲区协议的对象时,我们可以释放 GIL,因为缓冲区协议(正确实现时)会锁定缓冲区,并且缓冲区不能从另一个 Python 线程中销毁。其他 Python 对象没有这样的内置锁定。

    但如上所述,它可能不适用于您的代码。

    【讨论】:

    • 是的,cdef 确实有效。谢谢你的解释,有道理。我非常感谢关于是否解锁 GIL 的进一步讨论。在我的例子中,C++ 可以等待 IO 并且不使用任何 Python 对象,只使用原始内存缓冲区。所以我认为在这种情况下解锁 GIL 是合理的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 2018-02-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-18
    • 2017-07-21
    相关资源
    最近更新 更多