python - 使用python事件并与c++交互

标签 python c++ python-embedding

我正在测试在C / C++程序中嵌入Python,但是我缺乏理解。

测试程序很简单:

  • 初始化解释器;
  • 从启动Timer的文件中执行python脚本(每0.1秒增加一个变量);
  • 等待5秒(C++);
  • 从字符串执行python脚本,该脚本显示由Timer
  • 事件产生的值
  • 等待5秒(C++);
  • 完成;

  • 我观察到Timer事件是在方法Py_FinalizeEx()的调用期间执行的; ;

    所以:
  • c++程序在方法Py_FinalizeEx()处停止;
  • ,C++程序无法与Py_FinalizeEx()之前或之后的事件进行交互;

  • 在事件循环期间,C++程序如何与Python程序交互?

    python代码:

    from threading import *
    
    count = 0;
    
    def foo():
        global count
        t = Timer(0.1, foo)
        t.start()
        count= count+1;
        print("foo " + str(count), flush=True)
    
    foo()
    

    C++代码

    // initialize
    Py_InitializeEx(0);
    
    // execute foo.py
    PyRun_SimpleStringFlags("exec(open('foo.py'.encode('utf-8')).read())",nullptr);
    
    // wait 5s
    qDebug() << "wait 1 begin";
    QTime t = QTime::currentTime().addSecs(5);
    while(t > QTime::currentTime());
    qDebug() << "wait 1 end";
    
    // display value
    PyRun_SimpleStringFlags("print(count)",nullptr);
    
    // wait 5s
    qDebug() << "wait 2 begin";
    t = QTime::currentTime().addSecs(5);
    while(t > QTime::currentTime());
    qDebug() << "wait 2 end";
    
    qDebug() << "finalize: begin";
    Py_FinalizeEx();;
    qDebug() << "finalize: end";
    

    结果:
    foo 1
    wait 1 begin
    wait 1 end
    wait 2 begin
    1
    wait 2 end
    finalize: begin
    foo 2
    foo 3
    foo 4
    foo 5
    foo 6
    foo 7
    foo 8
    foo 9
    foo 10
    

    最佳答案

    伊卡洛斯的解决方案对我有帮助:

    Surround your "wait begin" and "wait end" with Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS



    这些宏对应于以下代码:

    // Py_BEGIN_ALLOW_THREADS
    {
      PyThreadState *save
      save = PyEval_SaveThread();
    // -------------
      qDebug() << "wait 1 begin";
      QTime t = QTime::currentTime().addSecs(5);
      while(t > QTime::currentTime());
      qDebug() << "wait 1 end";
    // Py_END_ALLOW_THREADS
      PyEval_RestoreThread(save);
    }
    // --------------
    

    我用Qt事件开发了另一个版本:
    from threading import *
    
    count = 0;
    
    def foo():
        global count
        if count < 20:
            t = Timer(1, foo)
            t.start()
        count= count+1;
        print("foo " + str(count), flush=True)
    
    foo()
    

    #ifndef TEST_H
    #define TEST_H
    
    #include <QObject>
    #include <QTimer>
    
    #undef slots
    #include <Python.h>
    #define slots
    
    class PythonTest : public QObject
    {
        Q_OBJECT
    
        PyThreadState *save;
    
        QTimer _timer;
        int count = 0;
    
    public:
        explicit PythonTest(QObject *parent = nullptr);
    
    signals:
    
    public slots:
        void read();
        void stop();
    };
    
    #endif // TEST_H
    

    #include "pythontest.h"
    #include <QDebug>
    
    PythonTest::PythonTest(QObject *parent) : QObject(parent)
    {
        qDebug() << "start: begin";
        Py_InitializeEx(0);
    
        PyRun_SimpleStringFlags("exec(open('foo.py'.encode('utf-8')).read())",nullptr);
    
        _save = PyEval_SaveThread();
    
        _timer.setInterval(5000);
        QObject::connect(&_timer, &QTimer::timeout, this, &PythonTest::read);
        _timer.start();
    
        qDebug() << "start: end";
    }
    
    void PythonTest::read()
    {
        qDebug() << "read: begin";
        if(_count>10)
        {
            QObject::disconnect(&_timer, &QTimer::timeout, this, &PythonTest::read);
            QObject::connect(&_timer, &QTimer::timeout, this, &PythonTest::stop);
        }
    
        PyEval_RestoreThread(_save);
        PyRun_SimpleStringFlags("print('read ' + str(count),flush=True)");
        _save = PyEval_SaveThread();
    
        _count++;
        qDebug() << "read: end";
    }
    
    void PythonTest::stop()
    {
        qDebug() << "stop: begin";
        QObject::disconnect(&_timer, &QTimer::timeout, this, &PythonTest::stop);
        PyEval_RestoreThread(_save);
    
        Py_FinalizeEx();
        qDebug() << "stop: end";
    }
    
    

    输出:
    start: begin
    foo 1
    start: end
    foo 2
    foo 3
    foo 4
    foo 5
    foo 6
    read: begin
    read: end
    read6
    foo 7
    foo 8
    foo 9
    foo 10
    read: begin
    read: end
    read10
    foo 11
    foo 12
    foo 13
    foo 14
    foo 15
    read: begin
    read: end
    read15
    foo 16
    foo 17
    foo 18
    foo 19
    foo 20
    read: begin
    read: end
    read20
    foo 21
    read: begin
    read: end
    read21
    read: begin
    read: end
    read21
    read: begin
    read: end
    read21
    ...
    

    关于python - 使用python事件并与c++交互,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59307739/

    相关文章:

    python - Scrapy下载文件报错302

    python - Django 类型错误 : allow_migrate() got an unexpected keyword argument 'model_name'

    python - 难以理解时间转换

    来自文件输入的c++数组

    c++ - Linux 中的代码执行时间

    python - 我在安装 texttract 时遇到错误

    c++ - 多线程应用程序c++中对象的引用计数

    c++ - 如何在 C++ 代码中捕获 python 标准输出

    c - 在C中嵌入python中导入keras时出错

    Python 嵌入 : PyImport_Import not from the current directory