Принуждение от Python не допускается без GIL - PullRequest
1 голос
/ 27 апреля 2020

Я пытаюсь вызвать функцию из библиотеки C ++, определенной следующим образом:

int somefunc(float timeout);

Я удвоил определение в файле pxd:

int somefunc(float timeout) nogil;

Но любая попытка вызов функции с nogil приводит к той же ошибке при цитонизации файла pyx:

 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

Я также попытался вызвать ее с типом c, что вызывает ту же ошибку.

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

Только с использованием поплавковых буквальных произведений. Как правильно вызывать эту функцию с действительной переменной Python?

1 Ответ

1 голос
/ 27 апреля 2020

Когда вы посмотрите на сгенерированный код для

timeout = 1.0
Q.somefunc(timeout)

, вы увидите, что timeout - это PyObject и __pyx_PyFloat_AsFloat вызывается для преобразования is в cdef-float. Однако во время этого преобразования может возникнуть исключение, и для этого необходим gil - таким образом, сообщение об ошибке.

Решением было бы принудительное приведение к float перед блоком nogil:

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

Теперь тайм-аут уже cdef-float, и преобразование в блоке nogil не требуется.


Немного не связано: я не вижу код и что такое Q, но большинство время, когда неправильно выпускать gil, когда код C / C ++ выполняет свою работу:

  1. Когда C / C ++ использует openMP для распараллеливания, удержание / не удержание GIL ничего не меняет для C / C ++ - код (вот пример: { ссылка }).

  2. Если поток не удерживает GIL, другой может уничтожить объекты, необходимые для C / C ++ - код для работы (например, Q или другие данные)

  3. Мы можем освободить GIL при работе с объектами, реализующими буферный протокол, поскольку буферный протокол (при правильной реализации) блокирует буфер и буфер не может быть уничтожен от другого Python -поток. Другие Python объекты не имеют такой встроенной блокировки.

Но, как отмечено выше, это может не относиться к вашему коду.

...