从 C 和Python中释放 GIL 和混合线程
在 C 扩展中发布 GIL:
给出一个 C 扩展代码,并且需要在Python解释器中与其他线程同时执行它。为此,必须释放并重新获取此全局解释器锁 (GIL) 。
代码#1:通过插入以下宏释放和重新获取 GIL
#include "Python.h"
...
PyObject *pyfunc(PyObject *self, PyObject *args)
{
...
Py_BEGIN_ALLOW_THREADS
// Threaded C code.
// Must not use Python API functions
...
Py_END_ALLOW_THREADS
...
return result;
}
混合来自 C 和Python的线程:
考虑一种情况,即给定程序涉及 C、 Python和线程的混合。但是一些给定的线程是从Python解释器控制之外的 C 创建的,并且某些线程也使用Python C API 中的函数。
那有什么解决办法?
如果混合使用Python、C 和线程,正确初始化和管理 Python 的全局解释器锁 (GIL)很重要。鉴于下面的代码解释了这种情况,他们的代码可以在 C 程序中的任何地方(在创建线程之前)使用。
代码#2:
#include
...
if (!PyEval_ThreadsInitialized())
{
PyEval_InitThreads();
}
...
对于任何涉及Python对象或Python C API 的 C,都需要先获取和发布 GIL。这可以使用PyGILState_Ensure()
和PyGILState_Release()
来执行,如下面的代码所示。对PyGILState_Ensure()
PyGILState_Release()
匹配调用。
代码#3:
...
// Make sure we own the GIL
// Use functions in the interpreter
PyGILState_STATE state = PyGILState_Ensure();
...
// Restore previous GIL state and return
PyGILState_Release(state);
...
笔记 :
一次完成这么多事情并不容易,涉及Python代码、C 代码及其线程的混合。为此,需要注意解释器已正确初始化,并且涉及解释器的 C 代码具有适当的 GIL 管理调用,这一切都应该工作。
此外, PyGILState_Ensure()
调用不会立即抢占或中断解释器。如果当前正在执行其他代码,则此函数将阻塞,直到该代码决定释放全局解释器锁 (GIL) 。