如何在Cython中为多线程C++类释放GIL?

Jac*_*son 6 c++ python multithreading cython gil

我有一个C++类,其中一些方法使用std :: thread,我可以通过Cython访问Python.你知道在我的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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

Dav*_*idW 7

您可能实际上并不需要使用nogil.GIL只会阻止多个Python线程同时运行.但是,如果你使用C++线程,他们可以很高兴地在后台运行而不管GIL,只要他们不尝试使用PyObjects或运行Python代码.所以我怀疑你是否误解了GIL,你可以不去思考它.

但是,假设您确实想要发布它,您需要做两件事:

  1. 将C++函数标记为nogil告诉Cython他们不需要GIL.请注意,这实际上并没有释放它 - 它只是让Cython知道如果它被释放它不是问题:

    cdef cppclass Rectange:
       Rectangle(int, int, int, int) nogil except +
       int getArea() nogil
       # ...
    
    Run Code Online (Sandbox Code Playgroud)
  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
    
    Run Code Online (Sandbox Code Playgroud)

    get_area变得稍微复杂一点,因为返回语句不能存在于with nogil块内,因为它涉及生成Python对象.