1、背景
简单说一下需求,Qt开发的上位机界面程序,需要调用Python编写的算法跑一个结果返回到界面上显示。
2、度娘出一篇博客,按照步骤进行环境搭建和简单的代码测试
环境搭建请参照如下博客地址:
博客:① https://blog.csdn.net/cholenmine/article/details/82854301
② https://blog.csdn.net/yinyuchen1/article/details/77775851
主要代码如下:
#include "Python.h" void MainWindow::test() { //进行初始化 Py_Initialize(); //如果初始化失败,返回 if(!Py_IsInitialized()) { qDebug()<<"11111111111111111111"; return ; } //加载模块,模块名称为myModule,就是myModule.py文件 PyObject *pModule = PyImport_ImportModule("myModule"); //如果加载失败,则返回 if(!pModule) { qDebug()<<"2222222222222222"; return; } //加载函数greatFunc PyObject * pFuncHello = PyObject_GetAttrString(pModule, "greatFunc"); //如果失败则返回 if(!pFuncHello) { qDebug()<<"3333333333333333333333"; return ; } }
3、根据目前的具体需求,我需要在开启一个线程来调用Python脚本,于是新建了一个线程类,调用方法还是用的上面的示例代码。
.h文件
#ifndef CALCSCORETHREAD_H #define CALCSCORETHREAD_H #include <QObject> #include <QThread> #include <Python.h> class CalcScoreThread : public QThread { Q_OBJECT public: CalcScoreThread(QObject *parent = nullptr); // html转化为PDF QString saveHtmlToPDF(QString str); protected: void run(); private: QString m_ScoreType; QString m_LabelPath; }; #endif // CALCSCORETHREAD_H
cpp文件
#include "CalcScoreThread.h" #include "LoggerInfo.h" #include <QCoreApplication> #include <QDateTime> #include <QDebug> #include <QDir> CalcScoreThread::CalcScoreThread(QObject *parent) : QThread(parent) { } void CalcScoreThread::SetScoreType(const QString &type) { m_ScoreType = type; } void CalcScoreThread::run() { Py_Initialize(); //测试集路径 QString setsPath = QCoreApplication::applicationDirPath()+"/datasets/Divide_Labels"; QString name ="main_SCORE"; LoggerInfo::GetInstance()->WriteLog("Start Import Module!"); PyObject* pModule = PyImport_ImportModule("main_SCORE"); if (!pModule) { qDebug() << "Cant open python file!"; return; } LoggerInfo::GetInstance()->WriteLog("Import Module Succ!"); //获取模块中的函数 PyObject* pFunc = PyObject_GetAttrString(pModule,"main"); if(!pFunc) { qDebug() << "Get function failed!"; return; } QString strEnv = "5,2,2,3"; PyObject* pArgs = PyTuple_New(4); PyTuple_SetItem(pArgs, 0, Py_BuildValue("s",m_ScoreType.toStdString().c_str())); PyTuple_SetItem(pArgs, 1, Py_BuildValue("s",m_LabelPath.toStdString().c_str())); PyTuple_SetItem(pArgs, 2, Py_BuildValue("s",setsPath.toStdString().c_str())); PyTuple_SetItem(pArgs, 3, Py_BuildValue("s",strEnv.toStdString().c_str())); PyObject* pReturn = PyObject_CallObject(pFunc, pArgs); if(pReturn) { qDebug() << "succ ------"; } Py_Finalize(); if(!strResult.isEmpty()) { emit SignalScoreResult(strResult); } }
现在问题来了:
① 第一次调用python脚本,能够正常调用并且得到结果。
② 不关闭主界面,接着进行第二次调用,软件直接崩溃,崩溃的行数是PyImport_ImportModule()函数,如下图所示:
最开始分析的原因:① 出现了空指针
② 第二次调用时,第一次的资源没有释放,占用python脚本,导致PyImport_ImportModule()函数不能将模块导入
4、最后差资料发现,因为我这里使用的是线程,C++多线调用python时必须要控制GIL
参照如下博客的方法才得以解决这个问题,对于小白初次线程中调用Python,鬼知道要控制什么GIL,虽然问题解决了,到现在都没去看GIL是个什么鬼
https://blog.csdn.net/qq_42938320/article/details/101770269