嵌入式 Python:多个子解释器不工作

Embedded Python: Multiple Sub-Interpreters not working

我正在尝试了解子解释器和 GIL。但是我的实验经常失败(相同的代码很少有效)。

从 SO 问题和少数站点收集信息,我有以下代码生成 2 个非 python 线程。这些线程中的每一个都被赋予了一个 python 子解释器。我想在这些线程中释放 GIL 并在 C++ 中调用一个 DLL 函数(尽管这个例子没有详细说明。这里我只是写到 stdout)。基本上我想在执行中看到并发性(非 Python DLL 调用)。

#include <iostream>
#include <thread>
#include <Python.h>

void worker(PyInterpreterState* interp, int n) 
{
    PyThreadState* ts;
    ts = PyThreadState_New(interp);

    PyThreadState_Swap(ts);

    PyThreadState* _save;
    _save = PyEval_SaveThread();

    std::cout << n << std::endl;  // Non-Python execution. My Focus.

    PyEval_RestoreThread(_save);

    PyThreadState_Swap(ts);

    PyThreadState_Clear(ts);
    PyThreadState_DeleteCurrent();

    return;
}


int main()
{
    try 
    {
        Py_Initialize();

        PyEval_InitThreads();

        PyThreadState* _main = PyThreadState_Get();

        PyThreadState* i1 = Py_NewInterpreter();
        PyThreadState* i2 = Py_NewInterpreter();

        std::thread t1(worker, i1->interp, 1);
        std::thread t2(worker, i2->interp, 2);

        t1.join();
        t2.join();

        PyThreadState_Swap(i1);
        PyThreadState_Clear(i1);
        Py_EndInterpreter(i1);
        PyThreadState_Swap(i2);
        PyThreadState_Clear(i2);
        Py_EndInterpreter(i2);

        PyThreadState_Swap(_main);

        Py_Finalize();
        return 0;
    }
    catch(std::exception& e)
    {
        std::cout << "Exception:" << std::endl << e.what() << std::endl;
    }
}

运行单线程一直工作。如图所示,当我 运行 2 个线程时,我得到以下任何输出。

  1. PyEval_SaveThread()
2
Fatal Python error: drop_gil: GIL is not locked
Python runtime state: initialized

Current thread 0x00002d08 (most recent call first):
<no Python frame>
  1. PyEval_SaveThread(),
1
Fatal Python error: PyEval_SaveThread: NULL tstate
Python runtime state: initialized

Current thread 0x00003eb8 (most recent call first):
<no Python frame>

一个线程成功,另一个失败。

  1. 很少见。相同的代码。
1
2

有人可以解释一下吗?需要帮忙。谢谢。

  1. 在您的 worker() 函数中,您调用了 PyThreadState_Swap()。 Python 文档 say 是:

The global interpreter lock must be held and is not released.

您必须在调用 PyThreadState_Swap() 之前获取 GIL,并在退出 worker() 之前释放它。

  1. 在您的主线程中,您等待线程终止,同时持有 GIL。这是一个死锁,因为线程需要获取 GIL 才能在 Python.
  2. 中完成任何有用的工作

请在 上查看我的回答,了解有关如何操作的详细工作说明,甚至 link 示例代码。

一旦你有了 GIL 和子解释器的线程状态,现在就可以安全地调用常规 Python API,你只需添加一个 PyEval_SaveThread()/PyEval_RestoreThread()对.