Python:GIL上下文 – 切换

所以,我通常非常了解Python中的全局解释器锁 (GIL)是如何工作的。 本质上,当解释器运行时,一个线程保持GIL为N刻度(其中N可以使用sys.setcheckinterval设置),此时GIL被释放而另一个线程可以获取GIL。 如果一个线程开始I / O操作,也会发生这种情况。

我有点困惑的是这一切是如何与C扩展模块一起工作的。

如果你有一个C扩展模块获取GIL,然后使用PyEval_EvalCode执行一些python代码,解释器PyEval_EvalCode可以释放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); 

是的,口译员可以随时发布GIL; 它会在解释了足够的指令后将其提供给其他一些线程,或者在它执行某些I / O时自动将其提供给其他线程。 请注意,从最近的Python 3.x开始,标准不再基于执行指令的数量,而是基于是否已经过了足够的时间。

要获得不同的效果,您需要一种方法以“primefaces”模式获取GIL,方法是在您明确释放GIL之前要求GIL不被释放。 到目前为止这是不可能的(但请参阅https://bitbucket.org/arigo/cpython-withatomic获取实验版本)。

正如Armin所说,GIL可以在PyEval_EvalCode释放。 当它返回时,它当然会再次获得。

最好的方法是确保您的代码可以处理它。 例如,在GIL可能被释放之前递增任何有C指针的对象。 另外,如果可能存在Python代码再次调用相同函数的情况,请小心。 如果你有另一个互斥锁,你可以很容易地陷入死锁。 使用递归安全的互斥锁,并在等待它们时,你应该释放GIL,以便原始线程可以释放这样的互斥锁。