如何在单独的QThread中使用QTimer [英] How to use a QTimer in a separate QThread

查看:809
本文介绍了如何在单独的QThread中使用QTimer的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些计算量大的任务,我想每5秒在一个循环中运行一次,而又不会阻塞主事件循环.为此,我打算使用QTimer和单独的线程来运行它.我已经尝试了以下代码,但到目前为止尚未奏效:

I have some computationally heavy task that I want to run in a loop after every 5 seconds without blocking the main event-loop. For this, I intend to use a QTimer and a separate thread to run it. I have tried the following code but it has not worked so far:

@pyqtSlot()
def heavy_task_function():
    # Sleep for 10 seconds to simulate heavy computation
    time.sleep(10)
    print "First Timer Fired"

if __name__ == "__main__":
    app = QCoreApplication.instance()
    if app is None:
        app = QApplication(sys.argv)

    threaded_timer = ModbusComThread(heavy_task_function)
    threaded_timer.start()

    sys.exit(app.exec_())

位置:

class ModbusComThread(QThread):

    def __init__(self, slot_function):
        QThread.__init__(self)
        self.slot_function = slot_function
        self.send_data_timer = None

    def run(self):
        print "Timer started on different thread"
        self.send_data_timer = QTimer(self)
        self.send_data_timer.timeout.connect(self.slot_function)
        self.send_data_timer.start(5000)

    def stop(self):
        self.send_data_timer.stop()

threaded_timer中的QTimer永远不会触发slot_function.我的线程架构正确吗?

The slot_function is never fired by the QTimer in threaded_timer. Is my threading architecture correct?

推荐答案

QTimer需要一个正在运行的事件循环.默认情况下,QThread.run()将启动线程的本地事件循环,但是如果您以完成的方式完全覆盖它,则不会发生-因此计时器事件将永远不会被处理.

A QTimer needs a running event-loop. By default, QThread.run() will start a local event-loop for the thread, but if you completely override it in the way that you have done, that won't happen - so the timer events will never be processed.

通常,当您需要本地事件循环时,应创建一个辅助对象来执行所有处理,然后使用

In general, when you need a local event-loop you should create a worker object to do all the processing and then use moveToThread to put it in a separate thread. If not, it's perfectly okay to override QThread.run().

下面的演示显示了如何执行此操作.请注意,在线程启动后创建计时器非常重要,否则它将在错误的线程中创建,并且其计时器事件不会被线程的事件循环处理.同样重要的是,工作线程和主线程之间的所有通信都是通过信号进行的,以确保线程安全.切勿尝试直接在主线程之外直接执行GUI操作,因为Qt完全不支持该操作.出于演示目的,在固定间隔后,主线程中的第二个计时器用于停止所有处理.如果有GUI,则用户通过按钮进行干预将实现相同的目的.

The demo below shows how to do this. Note that it's very important to create the timer after the thread has started, otherwise it would be created in the wrong thread and its timer-events wouldn't be processed by the thread's event-loop. It's also important that all communication between the worker thread and the main thread is done via signals, so as to ensure thread-safety. Never try to directly perform GUI operations outside the main thread, as Qt does not support that at all. For the purposes of the demo, a second timer in the main thread is used to stop all processing after a fixed interval. If there was a GUI, user intervention via a button would achieve the same thing.

演示:

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class ModbusComWorker(QObject):
    finished = pyqtSignal()

    def start(self):
        self._timer = QTimer(self)
        self._timer.timeout.connect(self.process)
        self._timer.start(2000)

    def stop(self):
        self._timer.stop()
        self.finished.emit()

    def process(self):
        print('processing (thread: %r)' % QThread.currentThread())
        QThread.sleep(3)

if __name__ == "__main__":

    app = QCoreApplication.instance()
    if app is None:
        app = QApplication(sys.argv)

    thread = QThread()
    worker = ModbusComWorker()
    worker.moveToThread(thread)

    def finish():
        print('shutting down...')
        thread.quit()
        thread.wait()
        app.quit()
        print('stopped')

    worker.finished.connect(finish)
    thread.started.connect(worker.start)
    thread.start()

    timer = QTimer()
    timer.setSingleShot(True)
    timer.timeout.connect(worker.stop)
    timer.start(15000)

    print('starting (thread: %r)' % QThread.currentThread())

    sys.exit(app.exec_())

输出:

starting (thread: <PyQt5.QtCore.QThread object at 0x7f980d096b98>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
shutting down...
stopped

这篇关于如何在单独的QThread中使用QTimer的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆