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