2013-04-27 88 views
8

所以,我通常對Python中的Global Interpreter Lock(GIL)的工作原理有很好的理解。實質上,在解釋器正在運行時,一個線程持有N個滴答的GIL(其中N可以使用sys.setcheckinterval設置),此時GIL被釋放,另一個線程可以獲取GIL。如果一個線程開始I/O操作,也會發生這種情況。Python:GIL上下文切換

我有點困惑的是,這一切如何與C擴展模塊一起工作。

如果您有一個C擴展模塊獲取GIL,然後使用PyEval_EvalCode執行一些python代碼,解釋程序是否可以釋放GIL並將其提供給其他線程?或者,獲取GIL的C線程是否永久保存GIL,直到PyEval_EvalCode返回並且GIL在C中明確釋放?

PyGILState gstate = PyGILState_Ensure(); 

.... 

/* Can calling PyEval_EvalCode release the GIL and let another thread acquire it?? */ 
PyObject* obj = PyEval_EvalCode(code, global_dict, local_dict); 

PyGILState_Release(gstate); 

回答

2

是的,解釋器總是可以釋放GIL;它會在解釋足夠的指令後將其提供給其他線程,或者如果它執行了某些I/O,則會自動進行。請注意,自從最近的Python 3.x以來,該標準不再基於已執行指令的數量,而是取決於是否已經過了足夠的時間。

爲了得到不同的效果,你需要的方式通過詢問GIL不被釋放,直到你釋放它明確地收購「原子」模式下,GIL。到目前爲止這是不可能的(但對於實驗版本,請參閱https://bitbucket.org/arigo/cpython-withatomic)。

+0

見我的[相關問題](http://stackoverflow.com/questions/29317120/forcing-a-thread-to-block-all-other-threads-from-executing)。我不明白如何解決你的陳述和Python Cookbook中的陳述之間看似不一致的地方。 – max 2015-03-29 00:04:20

+0

請參閱[Albert的答案](http://stackoverflow.com/a/29328066)。 – 2015-03-29 18:37:46

1

正如Armin所說,GIL可以在PyEval_EvalCode內發佈。當它返回時,它當然會再次獲得。

最好的方法是確保您的代碼可以處理該問題。例如,在GIL可能被釋放之前,增加你有C指針的任何對象。另外,如果可能出現Python代碼再次調用相同函數的情況,請小心。如果你有另一個互斥鎖,你可以很容易地死鎖。使用遞歸安全互斥鎖並等待它們時,您應該釋放GIL,以便原始線程可以釋放此類互斥鎖。