我试图将QThread和多进程结合起来,以便能够运行一些长时间的处理任务,同时保持我的GUI响应和更新进程的状态。
下面的代码没有更新标签,直到整个进程结束,所以我只看到最后一条消息。但是 print
工作正常。
import time
from PySide2.QtWidgets import QApplication, QLabel, QWidget, QPushButton, QHBoxLayout
from PySide2.QtCore import QThread, QObject, Signal
from multiprocessing import Process, Queue
class Worker():
"""Worker running in a Process"""
def __init__(self):
self.r0 = 2
self.N = 10
def setR0(self, r0):
self.r0 = r0
def setN(self, n):
self.N = n
def task(self, queue):
for i in range(self.N):
res = self.r0 ** i
queue.put(str(i) + ": " + str(res))
time.sleep(1)
queue.put("done")
class Runner(QObject):
"""Runner is running in a qthread"""
messageLogged = Signal(str)
def __init__(self, parent=None):
super().__init__(parent)
def exec_(self):
worker = Worker()
worker.setN(15)
worker.setR0(3)
queue = Queue()
process = Process(target=worker.task, args=(queue,))
process.start()
while True:
msg = queue.get()
if msg == "done":
self.messageLogged.emit("received 'done' signal")
break
self.messageLogged.emit(msg)
process.join()
if __name__ == '__main__':
app = QApplication([])
widget = QWidget()
layout = QHBoxLayout()
widget.setLayout(layout)
button = QPushButton("Run")
layout.addWidget(button)
label = QLabel("initial text")
layout.addWidget(label)
thread = QThread()
r = Runner()
r.messageLogged.connect(print)
r.messageLogged.connect(label.setText)
thread.started.connect(r.exec_)
def onButtonPushed():
thread.start()
button.setEnabled(False)
button.clicked.connect(onButtonPushed)
widget.show()
app.exec_()
为了保持界面的响应性,我还缺少什么?Process
但我如何发出一个信号来连接到我的标签?
我通过删除QThread并使用QTimer代替来解决我的问题。定时器以固定的时间间隔读取队列中的所有消息,然后让GUI再次响应一段时间,直到下次超时。
import time
from PySide2.QtWidgets import QApplication, QLabel, QWidget, QPushButton, QHBoxLayout
from PySide2.QtCore import QTimer
from multiprocessing import Process, Queue
class Worker():
"""Worker running in a Process"""
def __init__(self):
self.r0 = 2
self.N = 10
def setR0(self, r0):
self.r0 = r0
def setN(self, n):
self.N = n
def task(self, queue):
for i in range(self.N):
res = self.r0 ** i
queue.put(str(i) + ": " + str(res))
time.sleep(1)
print(i)
queue.put("done")
if __name__ == '__main__':
app = QApplication([])
widget = QWidget()
layout = QHBoxLayout()
widget.setLayout(layout)
button = QPushButton("Run")
layout.addWidget(button)
label = QLabel("initial text")
layout.addWidget(label)
button2 = QPushButton("Kill")
button2.setEnabled(False)
layout.addWidget(button2)
queue = Queue()
worker = Worker()
worker.setN(15)
worker.setR0(3)
process = Process(target=worker.task, args=(queue, ))
def read():
while not queue.empty():
msg = queue.get()
if msg == "done":
label.setText("received 'done' signal")
else:
label.setText(msg)
timer = QTimer()
timer.timeout.connect(read)
def onRunButtonPushed():
print("run clicked")
process.start()
timer.start(1000)
button.setEnabled(False)
button2.setEnabled(True)
def onKillButtonPushed():
process.terminate()
timer.stop()
button.clicked.connect(onRunButtonPushed)
button2.clicked.connect(onKillButtonPushed)
widget.show()
app.exec_()