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

时间:2017-03-13 12:02:55

标签: python c++ 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)

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)

1 个答案:

答案 0 :(得分:6)

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

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

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

    cdef cppclass Rectange:
       Rectangle(int, int, int, int) nogil except +
       int getArea() nogil
       # ...
    
  2. 使用Cython包装器类中的with nogil:块来标记实际释放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对象。