【问题标题】:Python: GIL context - switchingPython:GIL 上下文 - 切换
【发布时间】:2013-04-21 21:01:42
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

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

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

    【讨论】:

    • 见我的related question。我不明白如何解决您的陈述与 Python Cookbook 中的陈述之间看似不一致的问题。
    【解决方案2】:

    正如 Armin 所说,GIL 可以在 PyEval_EvalCode 内部发布。当它返回时,它当然又被获取了。

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

    【讨论】:

      猜你喜欢
      • 2021-04-07
      • 2011-07-23
      • 2017-06-13
      • 1970-01-01
      • 1970-01-01
      • 2017-09-09
      • 2011-07-27
      • 2011-11-18
      相关资源
      最近更新 更多