【问题标题】:Handling embedded Python interpreter calls with GIL and multi-threading使用 GIL 和多线程处理嵌入式 Python 解释器调用
【发布时间】:2020-08-05 14:18:43
【问题描述】:

星座/背景

动态链接 C++ 共享库 emb.so (2) 的 C++ 可执行文件 (1) 它又运行一个嵌入式 python 解释器 (3),它调用自定义 python 函数 (4)。

使用 pybind11 嵌入 Python 解释器 (3)。 从 C++ 调用 Python 函数可以简化为:

py::module::import("test").attr("my_func")();

可执行文件 (1) 有一个主循环,它可以在其中执行一些其他工作,但它会定期调用 python 函数。

观察

  • 变体1:如果我在python函数内部阻塞,python代码执行流畅快速,但主可执行循环明显阻塞
  • 变体 2:如果我在 python 函数内创建一个 python 线程以立即从该函数返回,则主可执行文件正在运行,但 python 代码运行速度极慢(我可以使用一张一张打印)

问题

为什么变体 2 这么慢,我该如何解决?

我的猜测是这与 GIL 有关,我尝试在返回主循环之前释放包装器 emb.so 中的 GIL,但如果没有段错误,我无法做到这一点。

有什么想法吗?

【问题讨论】:

    标签: python c++ multithreading pybind11 gil


    【解决方案1】:

    原来这和下面的问题有很大关系:

    Embedding python in multithreaded C application

    (见答案https://stackoverflow.com/a/21365656/12490068

    在调用嵌入式 Python 代码后,我通过显式释放 GIL 解决了这个问题:

    state = PyGILState_Ensure();
    // Call Python/C API functions...    
    PyGILState_Release(state);
    

    如果您在函数或其他 C++ 范围内执行此操作并且您正在创建 Python 对象,则必须确保在释放 GIL 后不调用 Python 对象的析构函数。 所以不要这样做:

    void my_func() {
        gil_state = PyGILState_Ensure();
        py::int_ ret = pymodule->attr("GiveMeAnInt")();
        PyGILState_Release(gil_state);
        return ret.cast<int>();
    }
    

    而是这样做

    void my_func() {
        int ret_value;
        gil_state = PyGILState_Ensure();
        {
            py::int_ ret = pymodule->attr("GiveMeAnInt")();
            ret_value = ret.cast<int>();
        }
        PyGILState_Release(gil_state);
        return ret_value;
    }
    

    【讨论】:

      猜你喜欢
      • 2017-12-12
      • 2018-10-05
      • 2021-03-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多