想讓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。 在內部,解釋器會執行週期性的線程切換,所以若是其餘線程在執行, 調用者最終仍是能夠運行的(儘管可能要先等一會)。接口