我有一些计算量很大的任务,我想在每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
从未被QTimer
的threaded_timer
解雇。我的线程架构是否正确?
QTimer
需要一个运行的事件循环。默认情况下,QThread.run()
将为该线程启动一个本地事件循环,但是如果你完全以你已经完成的方式覆盖它,那就不会发生 - 因此永远不会处理计时器事件。
通常,当您需要本地事件循环时,您应该创建一个工作对象来执行所有处理,然后使用moveToThread将其放在一个单独的线程中。如果没有,覆盖QThread.run()
是完全可以的。
下面的演示展示了如何执行此操作。请注意,在线程启动后创建计时器非常重要,否则它将在错误的线程中创建,并且它的timer-events不会被线程的事件循环处理。工作线程和主线程之间的所有通信都是通过信号完成的,这一点也很重要,以确保线程安全。永远不要尝试在主线程之外直接执行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