• 『Python CoolBook』C扩展库_其六_线程


    GIL操作

    想让C扩展代码和Python解释器中的其他进程一起正确的执行, 那么你就需要去释放并重新获取全局解释器锁(GIL)。

    在Python接口封装中去释放并重新获取全局解释器锁(GIL),此时本段程序失去GIL运行,其他线程可以无视本函数的运行而运行,直到Py_END_ALLOW_THREADS:

    #include "Python.h"
    ...
    
    PyObject *pyfunc(PyObject *self, PyObject *args) {
       ...
       Py_BEGIN_ALLOW_THREADS
       // Threaded C code.  Must not use Python API functions
       ...
       Py_END_ALLOW_THREADS
       ...
       return result;
    }
    

    只有当你确保没有Python C API函数在C中执行的时候你才能安全的释放GIL。 GIL需要被释放的常见的场景是在计算密集型代码中需要在C数组上执行计算(比如在numpy中) 或者是要执行阻塞的I/O操作时(比如在一个文件描述符上读取或写入时)。

    当GIL被释放后,其他Python线程才被允许在解释器中执行。 Py_END_ALLOW_THREADS 宏会阻塞执行直到调用线程重新获取了GIL。

    C和Python中的线程混用

    混合使用C、Python和线程, 有些线程是在C中创建的,超出了Python解释器的控制范围, 并且一些线程还使用了Python C API中的函数时,需要确保正确的初始化和管理Python的全局解释器锁(GIL)。

    要想这样,可以将下列代码放到你的C代码中并确保它在任何线程被创建之前被调用:

    #include <Python.h>
      ...
      if (!PyEval_ThreadsInitialized()) {
        PyEval_InitThreads();
      }
      ...
    

    对于任何调用Python对象或Python C API的C代码,确保你首先已经正确地获取和释放了GIL, 这可以用 PyGILState_Ensure()PyGILState_Release() 来做到,如下所示:

    ...
    /* Make sure we own the GIL */
    PyGILState_STATE state = PyGILState_Ensure();
    
    /* Use functions in the interpreter */
    ...
    /* Restore previous GIL state and return */
    PyGILState_Release(state);
    ...
    

    在涉及到C和Python的高级程序中,很多事情一起做是很常见的—— 可能是对C、Python、C线程、Python线程的混合使用。 只要你确保解释器被正确的初始化,并且涉及到解释器的C代码执行了正确的GIL管理,应该没什么问题。

    要注意的是调用 PyGILState_Ensure() 并不会立刻抢占或中断解释器。 如果有其他代码正在执行,这个函数被中断知道那个执行代码释放掉GIL。 在内部,解释器会执行周期性的线程切换,因此如果其他线程在执行, 调用者最终还是可以运行的(尽管可能要先等一会)。

  • 相关阅读:
    室内设计师招募中...
    winform控件部署于web中控件装载ie中
    Oracle10g在windows2003下双机热备安装
    购房风波(4)不了了之
    [原创]面向对象理解·抽象类和派生类理解和使用
    Infragistics NetAdvantage 2006 Volume 2 CLR 2.0曲折安装
    两个Javascript小tip
    PHP学习笔记之二
    C#开发语音机项目
    关于WebBrowser的DocumentText
  • 原文地址:https://www.cnblogs.com/hellcat/p/9093696.html
Copyright © 2020-2023  润新知