📜  从 C 和Python中释放 GIL 和混合线程

📅  最后修改于: 2022-05-13 01:54:54.836000             🧑  作者: Mango

从 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)