Python: GIL上下文切换

9
因此,我对Python中的全局解释器锁(GIL)的工作原理有一个相当好的理解。基本上,在解释器运行时,一个线程将保持GIL N个滴答声(其中N可以使用sys.setcheckinterval设置),然后释放GIL并允许另一个线程获取GIL。如果一个线程开始I/O操作,也会发生这种情况。
但是,我有点困惑的是,这一切与C扩展模块如何协同工作。
如果您有一个C扩展模块获取了GIL,并使用PyEval_EvalCode执行一些Python代码,那么解释器是否可以释放GIL并将其传递给其他线程?还是获取GIL的C线程将永久持有GIL,直到PyEval_EvalCode返回并在C中显式释放GIL?
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个回答

4
是的,解释器总是可以释放GIL;它会在解释足够的指令后将其交给其他线程,或者在执行某些I/O操作时自动释放。请注意,自从最近的Python 3.x版本以来,标准不再基于执行指令的数量,而是基于经过足够的时间。
要获得不同的效果,您需要一种以“原子”模式获取GIL的方法,即要求GIL在您明确释放之前不被释放。目前这是不可能的(但请参见https://bitbucket.org/arigo/cpython-withatomic进行实验版本)。

请查看我的相关问题。我不明白如何解决你的陈述和Python Cookbook中的陈述之间的矛盾。 - max

1
正如Armin所说,GIL可以在PyEval_EvalCode中释放。当它返回时,它当然会再次被获取。
最好的方法就是确保你的代码能够处理这个问题。例如,在GIL可能被释放之前,增加对任何具有C指针的对象的引用计数。此外,如果可能存在Python代码再次调用同一个函数的情况,请小心。如果你在那里有另一个互斥锁,你很容易陷入死锁。使用递归安全的互斥锁,在等待它们时,应该释放GIL,以便原始线程可以释放这些互斥锁。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接