Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Coercion from Python not allowed without the GIL

Tags:

python

cython

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?

like image 216
Aleksei Petrenko Avatar asked Jun 18 '26 08:06

Aleksei Petrenko


1 Answers

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.

like image 100
ead Avatar answered Jun 20 '26 22:06

ead



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!