python - 使用GIL和多线程处理嵌入式Python解释器调用

标签 python c++ multithreading pybind11 gil

星座/上下文:

一个C++可执行文件(1),它动态链接一个C++共享库emb.so(2)
依次运行嵌入式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代码运行得非常慢(我可以用打印代码观看for循环的迭代一个)

  • 问题:

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

    我的猜测是这与GIL有关,我尝试在返回到主循环之前释放包装emb.so中的GIL,但是我无法在没有段错误的情况下执行此操作。

    有任何想法吗?

    最佳答案

    事实证明,这与以下问题密切相关:

    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对象的desctructor。
    所以不要:
    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;
    }
    

    关于python - 使用GIL和多线程处理嵌入式Python解释器调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61367199/

    相关文章:

    c++ - C++ 函数返回错误值

    Android:多个 Intent 服务或一个具有多个 Intent 的 Intent 服务?

    python - 基本并行化。创建一个工作人员池,所有工作人员并行运行相同的功能

    python - py2exe和moviepy属性错误

    c++ - 如何删除指向(结构/对象)的指针而不破坏(结构/对象)内部的指针?

    python - grep、awk、bash 和 friend ?有什么工具可以处理这些数据吗?

    c++ - std::chrono 有多准确?

    multithreading - 异步调用的任务限制?

    python - SymPy 无法求解 Matlab 可以求解的方程

    python - 将所有 celery 任务的日志消息发送到单个文件