Как выпустить GIL в Cython для многопоточного класса C ++?

У меня есть класс C ++ с некоторыми методами, которые используют std :: thread, который я делаю доступным для Python через Cython. Вы знаете, где в моем коде Cython я бы хотел разместить директиву nogill? Я хотел бы поставить его, когда я объявляю методы класса или когда я создаю класс-оболочку Cython? Я использовал пример класса из документации Cython ниже:

Объявление класса:

cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle:
Rectangle() except +
Rectangle(int, int, int, int) except +
int x0, y0, x1, y1
int getArea()
void getSize(int* width, int* height)
void move(int, int)

Класс оболочки Cython:

cdef class PyRectangle:
cdef Rectangle c_rect      # hold a C++ instance which we're wrapping
def __cinit__(self, int x0, int y0, int x1, int y1):
self.c_rect = Rectangle(x0, y0, x1, y1)
def get_area(self):
return self.c_rect.getArea()
def get_size(self):
cdef int width, height
self.c_rect.getSize(&width, &height)
return width, height
def move(self, dx, dy):
self.c_rect.move(dx, dy)

3

Решение

Вы, вероятно, на самом деле не необходимость использовать nogil, GIL только останавливает одновременное выполнение нескольких потоков Python. Однако, учитывая, что вы используете потоки C ++, они вполне могут работать в фоновом режиме независимо от GIL, если они не пытаются использовать PyObjects или запустить код Python. Поэтому я подозреваю, что вы неправильно поняли GIL, и вы можете сойти с ума, не думая об этом.

Однако, если вы действительно хотите выпустить его, вам нужно сделать 2 вещи:

  1. Отметить функции C ++ как nogil сказать Cython, что им не нужен GIL. Обратите внимание, что это на самом деле не выпускает его — он просто сообщает Cython, что это не проблема, если он выпущен:

    cdef cppclass Rectange:
    Rectangle(int, int, int, int) nogil except +
    int getArea() nogil
    # ...
    
  2. использование with nogil: блоки в вашем классе-оболочке Cython, чтобы пометить области, где GIL фактически выпущен.

    cdef class PyRectangle:
    # ...
    def __cinit__(self, int x0, int y0, int x1, int y1):
    with nogil:
    self.c_rect = Rectangle(x0, y0, x1, y1)
    def get_area(self):
    cdef int result
    with nogil:
    result = self.c_rect.getArea()
    return result
    

    get_area становится немного сложнее, так как оператор возврата не может существовать внутри with nogil блок, поскольку он включает в себя создание объекта Python.

5

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]