即使主线程繁忙,后台线程中的 QTimer 是否也会更新?

问题描述 投票:0回答:1

假设我有一个 PyQt GUI 应用程序和一个使用

QTimer
在后台运行的
QThread
QTimer
设置为1秒间隔,无限运行。

现在主线程正忙于一些外部 C 库调用并阻塞 1 分钟。在此期间,

QTimer
会继续被触发并发出信号吗?

我正处于概念阶段,所以还没有代码可以显示。我知道在后台线程本身中进行大调用会更有意义。

python pyqt pyqt5 qthread qtimer
1个回答
2
投票

简而言之,是的,QTimer 将在另一个线程上更新,前提是您自己负责线程的生命周期并仅在最合适的时间退出它。还要小心

QTimer's
引用,因此它不会被 python 的垃圾收集器收集(您需要在某一时刻停止
QTimer
)。

现在,用一些代码来说明一个更实际的示例,以便您可以自己测试一下:

from PySide2.QtWidgets import QApplication, QMainWindow
from PySide2.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton
from PySide2.QtCore import QObject, QThread, QTimer, Signal

class TimerWorker(QObject):
    timeout = Signal(int)

    def __init__(self):
        QObject.__init__(self)
        self.count = 0

    def run(self):
        self.timer = QTimer()
        self.timer.setInterval(250)
        self.timer.timeout.connect(self.process)
        self.timer.start()

    def finished(self):
        self.timer.stop()

    def process(self):
        self.count += 1
        self.timeout.emit(self.count)

class Window(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        # Widgets
        self.scene = QWidget()
        self.label = QLabel("Count: 0")
        self.busyBt = QPushButton("Sleep")
        self.busyBt.clicked.connect(self.becomeBusy)

        # Scene
        layout = QVBoxLayout()
        layout.addWidget(self.label)
        layout.addWidget(self.busyBt)
        self.scene.setLayout(layout)
        self.setCentralWidget(self.scene)

        # Threads
        self.thread = QThread()
        self.worker = TimerWorker()
        self.worker.moveToThread(self.thread)
        self.worker.timeout.connect(self.processCount)
        self.thread.started.connect(self.worker.run)
        self.thread.finished.connect(self.worker.finished)
        self.thread.start()

    def becomeBusy(self):
        timeout = 5
        print('Main Thread: Sleeping for %d seconds...' % (timeout))
        QThread.sleep(timeout)
        print('Main Thread: Awaken')

    def processCount(self, count):
        self.label.setText("Count: %d" % (count))

    def closeEvent(self, evt):
        self.thread.quit()
        self.thread.wait()

if __name__ == '__main__':
    app = QApplication()
    win = Window()
    win.show()
    app.exec_()

在此示例中,我们启动一个

QThread
,它在
其他线程
上执行TimerWorker.run()(使用 moveToThread 方法)。每 0.25 秒,它会发出一个安排在主线程上的信号,以更新
QLabel
文本。

同时,用户可以单击

QPushButton
来停止主线程5秒。在此期间,应用程序将冻结。


通过执行脚本并单击

QPushButton
冻结主线程,
QTimer
继续运行并从 其他线程发出信号。但由于主线程正在休眠(或繁忙),因此信号永远不会被处理。该信号只会在主线程唤醒后才会被处理。

因此,如果您需要保持 GUI 始终响应客户端(并始终处理发出的信号),建议您在 QThread 侧完成所有

繁重工作
,以免应用程序冻结一段时间.

© www.soinside.com 2019 - 2024. All rights reserved.