Qt 调用Python脚本方法及遇到的问题

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

  

  

 

posted on 2020-03-31 16:20  jiangsion  阅读(6688)  评论(1编辑  收藏  举报

导航