如何在 Cython 中为多线程 C++ class 发布 GIL?
How to release the GIL in Cython for a multithreaded C++ class?
我有一个 C++ class 和一些使用 std::thread 的方法,我正在通过 Cython 使 Python 可以访问这些方法。你知道我想在我的 Cython 代码中的什么地方放置 nogill 指令吗?当我声明 class 方法或当我创建一个 Cython 包装器 class 时,我是否想放置它?我使用了以下 Cython 文档中的示例 class:
正在声明 class:
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 包装器 class:
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)
您可能实际上不需要来使用nogil
。 GIL 只会同时停止多个 Python 线程 运行。但是,如果您使用的是 C++ 线程,那么无论 GIL 是什么,它们都可以在后台愉快地 运行,前提是它们不尝试使用 PyObject
s 或 运行 Python 代码。所以我怀疑你误解了 GIL,你可以不去想它。
但是,假设您真的想要发布它,您需要做两件事:
将 C++ 函数标记为 nogil
以告诉 Cython 他们不需要 GIL。请注意,这实际上并没有释放它——它只是让 Cython 知道如果它被释放就不是问题:
cdef cppclass Rectange:
Rectangle(int, int, int, int) nogil except +
int getArea() nogil
# ...
在你的 Cython 包装器中使用 with nogil:
块 class 来标记 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
变得稍微复杂一些,因为 return 语句不能存在于 with nogil
块中,因为它涉及生成一个 Python 对象。
我有一个 C++ class 和一些使用 std::thread 的方法,我正在通过 Cython 使 Python 可以访问这些方法。你知道我想在我的 Cython 代码中的什么地方放置 nogill 指令吗?当我声明 class 方法或当我创建一个 Cython 包装器 class 时,我是否想放置它?我使用了以下 Cython 文档中的示例 class:
正在声明 class:
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 包装器 class:
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)
您可能实际上不需要来使用nogil
。 GIL 只会同时停止多个 Python 线程 运行。但是,如果您使用的是 C++ 线程,那么无论 GIL 是什么,它们都可以在后台愉快地 运行,前提是它们不尝试使用 PyObject
s 或 运行 Python 代码。所以我怀疑你误解了 GIL,你可以不去想它。
但是,假设您真的想要发布它,您需要做两件事:
将 C++ 函数标记为
nogil
以告诉 Cython 他们不需要 GIL。请注意,这实际上并没有释放它——它只是让 Cython 知道如果它被释放就不是问题:cdef cppclass Rectange: Rectangle(int, int, int, int) nogil except + int getArea() nogil # ...
在你的 Cython 包装器中使用
with nogil:
块 class 来标记 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
变得稍微复杂一些,因为 return 语句不能存在于with nogil
块中,因为它涉及生成一个 Python 对象。