Python:GIL上下文 - 切换

时间:2013-04-27 22:40:41

标签: python c python-3.x python-c-api cpython

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

我有点困惑的是这一切是如何与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 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

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

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