c++多线程QThreadpool调用Python脚本时崩溃报错的解决方案Patal error: init_importlib: can‘t impart _frozen_importlib
问题描述
c++Qt调用Python脚本自定义函数,在py_initialize时,崩溃退出。或者在线程中的某个接口处崩溃。感觉多线程对Python脚本是极不安全,很容易造成线程问题。因为我在main中主线程调用却没有任何问题……
Patal Python error: init_importlib: can’t impart _frozen_importlib
报错好像是MATLAB的库崩溃咯……

以下是示例代码,来自AI
#include <Python.h>
#include <iostream>
#include <string>
int main() {
// 初始化Python解释器
Py_Initialize();
// 添加包含自定义Python模块的目录到sys.path
std::string module_path = "/path/to/your/module"; // 替换为你的模块目录
std::string command = "import sys\nsys.path.append('" + module_path + "')";
PyRun_SimpleString(command.c_str());
// 导入Python模块
PyObject* pModule = PyImport_ImportModule("your_module_name"); // 替换为你的模块名
if (!pModule) {
PyErr_Print();
std::cerr << "Failed to load module." << std::endl;
return -1;
}
// 获取Python函数
PyObject* pFunc = PyObject_GetAttrString(pModule, "your_function_name"); // 替换为你的函数名
if (!pFunc || !PyCallable_Check(pFunc)) {
PyErr_Print();
std::cerr << "Cannot find function." << std::endl;
return -1;
}
// 准备调用Python函数的参数
PyObject* pArgs = PyTuple_New(2); // 假设函数需要两个参数
PyTuple_SetItem(pArgs, 0, PyLong_FromLong(1)); // 第一个参数
PyTuple_SetItem(pArgs, 1, PyLong_FromLong(2)); // 第二个参数
// 调用Python函数
PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
if (!pValue) {
PyErr_Print();
std::cerr << "Function call failed." << std::endl;
return -1;
}
// 处理返回值
long result = PyLong_AsLong(pValue);
std::cout << "Function returned: " << result << std::endl;
// 清理
Py_DECREF(pModule);
Py_DECREF(pFunc);
Py_DECREF(pArgs);
Py_DECREF(pValue);
// 关闭Python解释器
Py_Finalize();
return 0;
}
解决方案
经过几天的测试,可能有几处需要注意的地方
1.pyObiect那些不一定要使用Py_DECREF来释放,没调用挺好,多线程一调用就有可能崩溃,调用的顺序也非常有讲究,最好就是用完就调用释放,多线程时,我就都没有调用释放函数;
2.py_initialize这个函数很关键,必须在线程中启用,之后可以写上面的那些pyobject等等语句。还有一种现象就是,多线程时,很容易崩在前面准备的位置;所以这里的解决方法就是将py_initialize函数放在一个函数中,并加锁。意思是一个个线程依次调用。
3.py_finitialize函数很奇怪。理论上跟initialize函数成对出现才对,但是多线程就是不能调,调用了该函数,程序就会出错崩溃。所以多线程也不调用该函数,至于为什么,真的不清楚…
4.PyGILState_Ensure函数也很诡异,跟PyGILState_Release成对出现,理论上在同一个函数中,怎么都会执行,最后跑着跑着,所有线程就被卡死死锁了,估计根本就没释放啊!在多线程中也没有用。
#include <Python.h>
#include <iostream>
#include <thread>
void call_python_function() {
try {
// 尝试获取GIL
PyGILState_STATE gstate = PyGILState_Ensure();
std::cout << "GIL acquired successfully." << std::endl;
// 执行Python代码...
// 释放GIL
PyGILState_Release(gstate);
std::cout << "GIL released successfully." << std::endl;
} catch (const std::exception& e) {
std::cerr << "Exception occurred: " << e.what() << std::endl;
} catch (...) {
std::cerr << "Unknown exception occurred." << std::endl;
}
}
int main() {
// 初始化Python
Py_Initialize();
// 创建并启动线程
std::thread t(call_python_function);
t.join();
// 清理Python
Py_Finalize();
return 0;
}
最后总结,就是多线程在py_initialize函数前面加锁,不用Py_DECREF,py_finitialize,PyGILState_Ensure,PyGILState_Release。

这是我这几天测试的结果,至少目前程序运行还是正常的,会不会有其他问题,以后再更吧。
编辑:myhappyandy
更多推荐
所有评论(0)