• 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

      

      

  • 相关阅读:
    Linux 进程管理
    强大的bat文件搞定系统所有问题
    Java多线程设计要点
    Linux 内核
    Linux 文件和目录管理之列出、删除、复制、移动及改名
    命令dd 及简单应用
    Transferring Files with SFTP or SCP
    简述Linux文件搜索
    加强Eclipse代码自动提示的方法
    Cisco交换机配置新手篇之端口配置
  • 原文地址:https://www.cnblogs.com/jiangson/p/12606000.html
Copyright © 2020-2023  润新知