想让C扩展代码和Python解释器中的其余进程一块儿正确的执行, 那么你就须要去释放并从新获取全局解释器锁(GIL)。数组
在Python接口封装中去释放并从新获取全局解释器锁(GIL),此时本段程序失去GIL运行,其余线程能够无视本函数的运行而运行,直到Py_END_ALLOW_THREADS:安全
#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; }
只有当你确保没有Python C API函数在C中执行的时候你才能安全的释放GIL。 GIL须要被释放的常见的场景是在计算密集型代码中须要在C数组上执行计算(好比在numpy中) 或者是要执行阻塞的I/O操做时(好比在一个文件描述符上读取或写入时)。函数
当GIL被释放后,其余Python线程才被容许在解释器中执行。 Py_END_ALLOW_THREADS
宏会阻塞执行直到调用线程从新获取了GIL。spa
混合使用C、Python和线程, 有些线程是在C中建立的,超出了Python解释器的控制范围, 而且一些线程还使用了Python C API中的函数时,须要确保正确的初始化和管理Python的全局解释器锁(GIL)。线程
要想这样,能够将下列代码放到你的C代码中并确保它在任何线程被建立以前被调用:code
#include <Python.h> ... if (!PyEval_ThreadsInitialized()) { PyEval_InitThreads(); } ...
对于任何调用Python对象或Python C API的C代码,确保你首先已经正确地获取和释放了GIL, 这能够用 PyGILState_Ensure()
和 PyGILState_Release()
来作到,以下所示:对象
... /* Make sure we own the GIL */ PyGILState_STATE state = PyGILState_Ensure(); /* Use functions in the interpreter */ ... /* Restore previous GIL state and return */ PyGILState_Release(state); ...
在涉及到C和Python的高级程序中,不少事情一块儿作是很常见的—— 多是对C、Python、C线程、Python线程的混合使用。 只要你确保解释器被正确的初始化,而且涉及到解释器的C代码执行了正确的GIL管理,应该没什么问题。blog
要注意的是调用 PyGILState_Ensure()
并不会马上抢占或中断解释器。 若是有其余代码正在执行,这个函数被中断知道那个执行代码释放掉GIL。 在内部,解释器会执行周期性的线程切换,所以若是其余线程在执行, 调用者最终仍是能够运行的(尽管可能要先等一会)。接口