简体   繁体   中英

Coercion from Python not allowed without the GIL

I am trying to call a function from a C++ library defined like this:

int somefunc(float timeout);

I doubled a definition in the pxd file:

int somefunc(float timeout) nogil;

But any attempt to call the function with nogil leads to the same error when cythonizing the pyx file:

 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

I also tried calling it with a ctype, which causes the same error.

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

Only using a float literal works. What is the right way to call this function with an actual Python variable?

When you look at the generated code for

timeout = 1.0
Q.somefunc(timeout)

you will see, that timeout is PyObject and __pyx_PyFloat_AsFloat is called to convert is to cdef-float. However during this conversion an exception can be raised and for this the gil is needed - thus the error message.

The solution would be to force coercion to float before the nogil-block:

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

now timeout is already cdef-float and no conversion is needed in the nogil-block.


Slightly unrelated: I cannot see the code and what Q is, but most of the time it is wrong to release gil when letting C/C++ code do the work:

  1. When C/C++ uses openMP for parallelization, holding/not holding GIL doesn't change anything for the C/C++-code (here is an example: https://stackoverflow.com/a/60012137/5769463 ).

  2. When the thread doesn't hold GIL the other could destroy objects needed for the C/C++-code to work (like Q or other data)

  3. We can release GIL when working with objects implementing buffer protocol, because buffer protocol (when correctly implemented) locks the buffer and the buffer cannot be destroyed from another Python-Thread. Other Python objects have no such locking built-in.

But as noted above, it might not apply to your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM