Embedded Python: Multiple Sub-Interpreters not working

99封情书 提交于 2020-01-16 19:35:08

问题


I'm trying to understand sub-interpreters and GIL. But my experiment is failing often(The same code rarely works).

Gathering info from SO questions and few sites, I have the following code which spawns 2 non-python threads. Each of these threads are given a python sub-interpreter. I want to release GIL inside these threads and call a DLL function in C++(though this example does not detail that. Here I just write to stdout). Basically I want to see concurrency in the execution(Non-Python DLL invocation).

#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;
    }
}

Running a single thread works all the time. When I run 2 threads as shown, I get any of the following outputs.

  1. In 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. In PyEval_SaveThread(),
1
Fatal Python error: PyEval_SaveThread: NULL tstate
Python runtime state: initialized

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

Either of the thread succeeds, the other one fails.

  1. Rarely works. The same code.
1
2

Can someone shed some light on this? Need help. Thanks.


回答1:


  1. In your worker() function, you call PyThreadState_Swap(). The Python docs say that:

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

You must acquire the GIL before calling PyThreadState_Swap() and release it before exiting worker().

  1. In your main thread, you wait for the threads to terminate while holding the GIL. This is a deadlock as the threads will need to acquire the GIL to do any useful work in Python.

Please see my answer at https://stackoverflow.com/a/26570708/99279 for detailed working instructions on how to do that, and even a link to sample code.

Once you have the GIL, and the thread state for for the sub interpreter, so that it is now safe to call the regular Python API, you can just add a PyEval_SaveThread()/PyEval_RestoreThread() pair.



来源:https://stackoverflow.com/questions/59666352/embedded-python-multiple-sub-interpreters-not-working

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!