嵌入式 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 个线程时,我得到以下任何输出。
- 在
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>
- 在
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
2
有人可以解释一下吗?需要帮忙。谢谢。
- 在您的
worker()
函数中,您调用了 PyThreadState_Swap()
。 Python 文档 say 是:
The global interpreter lock must be held and is not released.
您必须在调用 PyThreadState_Swap()
之前获取 GIL,并在退出 worker()
之前释放它。
- 在您的主线程中,您等待线程终止,同时持有 GIL。这是一个死锁,因为线程需要获取 GIL 才能在 Python.
中完成任何有用的工作
请在 上查看我的回答,了解有关如何操作的详细工作说明,甚至 link 示例代码。
一旦你有了 GIL 和子解释器的线程状态,现在就可以安全地调用常规 Python API,你只需添加一个 PyEval_SaveThread()
/PyEval_RestoreThread()
对.
我正在尝试了解子解释器和 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 个线程时,我得到以下任何输出。
- 在
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>
- 在
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
2
有人可以解释一下吗?需要帮忙。谢谢。
- 在您的
worker()
函数中,您调用了PyThreadState_Swap()
。 Python 文档 say 是:
The global interpreter lock must be held and is not released.
您必须在调用 PyThreadState_Swap()
之前获取 GIL,并在退出 worker()
之前释放它。
- 在您的主线程中,您等待线程终止,同时持有 GIL。这是一个死锁,因为线程需要获取 GIL 才能在 Python. 中完成任何有用的工作
请在 上查看我的回答,了解有关如何操作的详细工作说明,甚至 link 示例代码。
一旦你有了 GIL 和子解释器的线程状态,现在就可以安全地调用常规 Python API,你只需添加一个 PyEval_SaveThread()
/PyEval_RestoreThread()
对.