QT多线程调用python

本文介绍如何在C++中使用多线程安全地调用Python脚本,包括初始化Python解释器、管理全局解释器锁(GIL)以及在子线程中正确加载和使用Python模块的过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于Python解释器有全局解释所GIL的原因,导致在同一时刻只能有一个线程拥有解释器,所以在C++多线程调用python脚本时,需要控制GIL,线程获取GIL。
所以一个程序里,无论有多少条线程调用python,python只能初始化一次。
每次线程要调用python时,都要拥有GIL。

//python只需要初始化一次
void PythonHandler::PythonInit()
{
    if( !Py_IsInitialized() )
    {
        //1.初始化Python解释器,这是调用操作的第一步
        Py_Initialize();
        if( !Py_IsInitialized() ){
            qDebug("初始化Python解释器失败");
         }else{
            // 初始化线程支持
           PyEval_InitThreads();
           // 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。
           PyEval_ReleaseThread(PyThreadState_Get());
           qDebug("初始化Python解释器成功");
        }
    }
}

//将全局解释器锁和线程的相关操作用类封装
#ifndef PYTHREADSTATELOCK_H
#define PYTHREADSTATELOCK_H
#include "Python.h"

class PyThreadStateLock
{
public:    
    PyThreadStateLock(void)
    {
        _save = nullptr;
        nStatus = 0;
        nStatus = PyGILState_Check() ;   //检测当前线程是否拥有GIL
        PyGILState_STATE gstate;
        if ( !nStatus )
        {
            gstate = PyGILState_Ensure();   //如果没有GIL,则申请获取GIL
            nStatus = 1;
        }
        _save = PyEval_SaveThread();
        PyEval_RestoreThread(_save);
    }
    ~PyThreadStateLock(void)
    {
        _save = PyEval_SaveThread();
        PyEval_RestoreThread(_save);
        if (nStatus)
        {
            PyGILState_Release(gstate);    //释放当前线程的GIL
        }
    }

private:
    PyGILState_STATE gstate;
    PyThreadState *_save;
    int nStatus;

};

#endif // PYTHREADSTATELOCK_H

然后我们就可以在子线程调用python

//加载模块
void PythonHandler::PythonInsmod(QString pyfname)
{
    class PyThreadStateLock PyThreadLock;//获取全局锁

    // Import
    if ( -1 == PyRun_SimpleString("import os") ) {
        qCritical()<<"Python缺少OS库";
        return ;
    }
    if ( -1 == PyRun_SimpleString("import math") ) {
        qCritical()<<"Python缺少Math库";
        return ;
    }
    if ( -1 == PyRun_SimpleString("import sys") ) {
        qCritical()<<"Python缺少Sys库";
        return ;
    }
    if ( -1 == PyRun_SimpleString("import time") ) {
        qCritical()<<"Python缺少Time库";
        return ;
    }
    if ( -1 == PyRun_SimpleString("from PIL import Image") ) {
        qCritical()<<"Python缺少PIL库";
        return ;
    }
    if ( -1 == PyRun_SimpleString("import tensorflow as tf") ) {
        qCritical()<<"Python缺少Tensorflow库";
        return ;
    }
    if ( -1 == PyRun_SimpleString("import numpy as np") ) {
        qCritical()<<"Python缺少Numpy库";
        return ;
    }
    if ( -1 == PyRun_SimpleString("import cv2") ) {
        qCritical()<<"Python缺少OpenCV库";
        return ;
    }

    // 导入py模块
 	m_module = PyImport_ImportModule(pyfname.toLocal8Bit().data());

    if ( nullptr != m_module ) {
        qDebug()<<"加载Python文件成功";
    } else {
        qCritical()<<"加载Python文件失败"<<pyfname;
        return ;
    }

    // 载入方法
    m_detection = PyObject_GetAttrString(m_module, "detection");
    if ( nullptr != m_detection && PyCallable_Check( m_detection ) ) {
        qDebug()<<"加载Python方法成功";
    } else {
        qCritical()<<"加载Python方法失败";
        return ;
    }
}

后续,就可以在子线程尽情地调用python函数了
本文参考:C++ 多线程调用Python脚本

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值