gpt4 book ai didi

python - Pyqt5 中的 QThreads : is this the correct C++ to Python translation of the official QThread docs?

转载 作者:行者123 更新时间:2023-12-01 09:24:40 29 4
gpt4 key购买 nike

关于如何实例化和使用 QThread 的官方文档可以在这里找到:
http://doc.qt.io/qt-5/qthread.html

该文档描述了两种基本方法:(1) 工作对象方法和 (2) QThread子类方法。我在几篇文章中读到第二种方法不好,所以让我们关注第一种。

编辑:
@ekhumoro 给我指出了以下有趣的文章:https://woboq.com/blog/qthread-you-were-not-doing-so-wrong.html
.显然,两种方法(1)和(2)都有各自的优点:

As a rule of thumb:

  • If you do not really need an event loop in the thread, you should subclass.
  • If you need an event loop and handle signals and slots within the thread, you may not need to subclass.


  • 由于我确实需要 QApplication 线程和新 QThread 之间的某种通信(而且我相信信号槽是一种很好的通信方式),我将使用工作对象方法。

    1. C++ 中的工作对象方法

    我已经复制粘贴了工作对象方法的 C++ 代码(来自官方 Qt5 文档,请参阅 http://doc.qt.io/qt-5/qthread.html ):
    class Worker : public QObject
    {
    Q_OBJECT

    public slots:
    void doWork(const QString &parameter) {
    QString result;
    /* ... here is the expensive or blocking operation ... */
    emit resultReady(result);
    }

    signals:
    void resultReady(const QString &result);
    };

    class Controller : public QObject
    {
    Q_OBJECT
    QThread workerThread;
    public:
    Controller() {
    Worker *worker = new Worker;
    worker->moveToThread(&workerThread);
    connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
    connect(this, &Controller::operate, worker, &Worker::doWork);
    connect(worker, &Worker::resultReady, this, &Controller::handleResults);
    workerThread.start();
    }
    ~Controller() {
    workerThread.quit();
    workerThread.wait();
    }
    public slots:
    void handleResults(const QString &);
    signals:
    void operate(const QString &);
    };

    2. Python 中的工作对象方法

    我努力将给定的 C++ 代码翻译成 Python。如果你安装了 Python 3.6 和 PyQt5,你可以简单地复制粘贴这段代码并在你的机器上运行它。它应该工作。
    import sys
    from PyQt5.QtWidgets import *
    from PyQt5.QtCore import *
    from PyQt5.QtGui import *

    class Worker(QObject):

    resultReady = pyqtSignal(str)

    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    @pyqtSlot(str)
    def doWork(self, param):
    result = "hello world"
    print("foo bar")
    # ...here is the expensive or blocking operation... #
    self.resultReady.emit(result)


    class Controller(QObject):

    operate = pyqtSignal(str)

    def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)

    # 1. Create 'workerThread' and 'worker' objects
    # ----------------------------------------------
    self.workerThread = QThread()
    self.worker = Worker() # <- SEE NOTE(1)
    self.worker.moveToThread(self.workerThread)

    # 2. Connect all relevant signals
    # --------------------------------
    self.workerThread.finished.connect(self.worker.deleteLater)
    self.workerThread.finished.connect(lambda: print("workerThread finished.")) # <- SEE NOTE(2)
    self.operate.connect(self.worker.doWork)
    self.worker.resultReady.connect(self.handleResults)

    # 3. Start the thread
    # --------------------
    self.workerThread.start()

    def __del__(self):
    self.workerThread.quit()
    self.workerThread.wait()

    @pyqtSlot(str)
    def handleResults(self, param):
    print(param)
    # One way to end application
    # ---------------------------
    # global app # <- SEE
    # app.exit() # NOTE(3)

    # Another way to end application
    # -------------------------------
    self.workerThread.quit() # <- SEE NOTE(4)
    self.thread().quit()


    if __name__ == '__main__':
    app = QCoreApplication([])
    controller = Controller()
    controller.operate.emit("foo") # <- SEE NOTE(5)
    sys.exit(app.exec_())

    注(1):
    最初我实现了 worker变量作为构造函数中的局部变量。我实际上是在将 C++ 示例翻译成 Python,并且这个变量也是 C++ 示例中的局部变量。
    正如您在@pschill 的评论中看到的那样,这个局部变量是垃圾收集的,因此我无法让线程运行。进行更改后,我得到了预期的输出。

    笔记2):
    我已添加此行以准确了解 workerThread 的时间。完成。

    注(3):
    显然我需要添加这两条代码行 global appapp.exit()handleResults(..)投币口。谢谢@Matic 指出这一点!

    注(4):
    我已经(通过一些文档)发现了这种结束应用程序的方法。第一个代码行结束 workerThread (通过杀死它的事件循环)。第二个代码行结束 mainThread (也通过杀死它的事件循环)。

    注(5):
    在 Windows 控制台中运行代码时,什么都没有发生(它只是挂起)。根据@pschill 的建议(请参阅下面的评论),我添加了此代码行以确保 doWork()函数被调用。

    3. 我的问题
  • 首先,我想知道我从 C++ 到 Python 的翻译是否正确。请告诉我我在哪里犯了错误(如果你发现任何错误)。
  • 添加代码行 global appapp.exit()handleResults(..)插槽解决了挂起问题。但是背景究竟发生了什么?这些代码行是否会杀死工作线程?还是主 QApplication 线程?
  • 有没有办法在不杀死主 QApplication 线程的情况下杀死工作线程?


  • 4.一些答案

    1.还是不确定..

    2. 我相信 app.exit()杀死主线程,然后杀死工作线程,因为它是守护进程类型。我发现worker线程是deamon类型的,因为我插入了代码行 print(threading.current_thread())doWork(..)功能。它打印了 <_DummyThread(Dummy-1, started daemon 9812)> .当程序退出时,所有守护线程都会自动终止。

    3. 是的,我找到了方法! QThread::quit()函数是你的 friend 。官方文档是这样说的:

    void QThread::quit()
    Tells the thread's event loop to exit with return code 0 (success). Equivalent to calling QThread::exit(0).
    This function does nothing if the thread does not have an event loop.
    [http://doc.qt.io/qt-5/qthread.html#quit]



    所以我的函数 handleResults(..)现在看起来像这样:
        @pyqtSlot(str)
    def handleResults(self, param):
    print(param)
    self.workerThread.quit() # Kill the worker thread
    self.thread().quit() # Kill the main thread

    我已经通过在 Controller(..) 的构造函数中插入这一行来检查工作线程的终止情况。 :
        self.workerThread.finished.connect(lambda: print("workerThread finished."))

    我确实按预期打印了该行。我还尝试以类似的方式检查主线程的终止:
        self.thread().finished.connect(lambda: print("mainThread finished."))

    不幸的是,这条线没有打印出来。为什么?

    在此我提供我当前的系统设置:
    >  Qt5 ( QT_VERSION_STR = 5.10.1)
    >  PyQt5 ( PYQT_VERSION_STR = 5.10.1)
    >  Python 3.6.3
    >  Windows 10、64 位

    最佳答案

    您的 Python 示例应用程序需要以某种方式退出,否则它只会在 Controller 之后出现。对象已初始化。

    最简单的方法是更改​​handleResults在您的示例中执行以下操作:

    @pyqtSlot(str)
    def handleResults(self, param):
    print(param)
    global app
    app.exit()

    希望能帮助到你。

    关于python - Pyqt5 中的 QThreads : is this the correct C++ to Python translation of the official QThread docs?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50531797/

    29 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com