9

因此,我通常对 Python 中的全局解释器锁(GIL) 的工作原理有很好的了解。本质上,当解释器运行时,一个线程将 GIL 保存 N 个刻度(N可以使用 设置sys.setcheckinterval),此时 GIL 被释放,另一个线程可以获取 GIL。如果一个线程开始 I/O 操作,也会发生这种情况。

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

如果您有一个获取 GIL 的 C 扩展模块,然后使用 执行一些 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);
4

2 回答 2

4

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

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

于 2013-04-28T12:03:43.403 回答
1

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

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

于 2013-10-15T15:41:19.197 回答