python - 如何在单独的 QThread 中使用 QTimer

标签 python python-2.7 pyqt5 qthread qtimer

我有一些计算量大的任务,我想每 5 秒循环运行一次,而不阻塞主事件循环。为此,我打算使用 QTimer 和单独的线程来运行它。我已经尝试过以下代码,但到目前为止还没有工作:

@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()

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

最佳答案

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

一般来说,当您需要本地事件循环时,您应该创建一个工作对象来完成所有处理,然后使用 moveToThread将其放在单独的线程中。如果没有,完全可以重写QThread.run()

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

演示:

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

关于python - 如何在单独的 QThread 中使用 QTimer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55651718/

相关文章:

python - 计算特定 bin 中的元素数

Python for循环迭代 'i'

python - 如何在 SublimeREPL 上运行 Python 代码

windows - 如何在 Python 命令行应用程序上创建静态标题/边框

javascript - 将文本预测脚本 [Markov Chain] 从 javascript 转换为 python

python - boto3 ec2中的分页描述实例

python - TypeError:setText(self,str):参数1具有意外类型 'tuple'

python - 在PyQt5中关闭/打开vlc播放器后如何使用QWinThumbnailToolBar恢复任务栏缩略图

python - pyQt : How do I update a label?

python - 默认参数不起作用