当在目标函数run_event()
中实现队列时,我无法停止进程。需要队列从目标函数返回值。可以在没有队列的情况下停止该进程。
from PyQt5.QtWidgets import QHBoxLayout, QApplication, QWidget, QPushButton
from PyQt5.QtCore import QThread
from multiprocessing import Process, Queue,
def run_event(params, queue):
"""Run some task that cant be stopped by polling
returns a dataframe
"""
out = arbritrarySolver(params) # Runs a solver that returns a dataframe
queue.put(out)
class Worker(QObject):
def __init__(self, params):
super().__init__()
self.params = params
def stop_work(self):
self.process.terminate()
def start_work(self):
self.queue = Queue()
self.process = Process(target=run_event, args=(self.params, self.queue))
self.process.start()
output = self.queue.get() # output of run_event
class Gui(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def start_event(self):
self.worker_thread = QThread()
self.obj = worker.Worker(params)
self.obj.moveToThread(self.worker_thread)
self.worker_thread.started.connect(self.obj.start_work)
self.stopButton.clicked.connect(self.obj.stop_work)
self.worker_thread.start()
def initUI(self):
self.runButton = QPushButton('Run', self)
self.runButton.clicked.connect(self.start_event)
hbox = QHBoxLayout()
hbox.addWidget(self.runButton)
self.setLayout(hbox)
self.show()
if __name__ == "__main__":
app = QApplication(sys.argv)
ex = Gui()
sys.exit(app.exec_())
我如何实现在实现队列时用停止按钮中断run_event()
的解决方案?
答案 0 :(得分:3)
问题在于,当您使用self.queue.get()时,您正在阻塞工作线程所在的辅助线程,而可能的策略是使用计时器检查队列的状态,并相应地发送将结果发送到GUI的信号。
from functools import partial
import multiprocessing as mp
from PyQt5 import QtCore, QtWidgets
from foo_package import arbritrarySolver
def run_event(params, queue):
"""Run some task that cant be stopped by polling
returns a dataframe
"""
out = arbritrarySolver(params) # Runs a solver that returns a dataframe
queue.put(out)
class Worker(QtCore.QObject):
resultChanged = QtCore.pyqtSignal(object)
finished = QtCore.pyqtSignal()
def __init__(self):
super().__init__()
self.m_timer = QtCore.QTimer(self)
self.m_timer.timeout.connect(self.check_result)
self.process = None
@QtCore.pyqtSlot()
def stop_work(self):
if isinstance(self.process, mp.Process):
self.process.terminate()
@QtCore.pyqtSlot(object)
def start_work(self, params):
self.queue = mp.Queue()
self.process = mp.Process(target=run_event, args=(params, self.queue))
self.process.start()
self.m_timer.start(0)
@QtCore.pyqtSlot()
def check_result(self):
if not self.process.is_alive():
self.finished.emit()
self.m_timer.stop()
if not self.queue.empty():
r = self.queue.get(block=False)
self.resultChanged.emit(r)
class Gui(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.worker_thread = QtCore.QThread(self)
self.worker_thread.start()
self.obj = Worker()
self.obj.moveToThread(self.worker_thread)
self.obj.resultChanged.connect(self.onResultChanged)
self.obj.finished.connect(self.onFinished)
self.initUI()
@QtCore.pyqtSlot()
def start_event(self):
params = "aaa", "bbb"
wrapper = partial(self.obj.start_work, params)
QtCore.QTimer.singleShot(0, wrapper)
self.runButton.setDisabled(True)
self.stopButton.setDisabled(False)
@QtCore.pyqtSlot()
def onFinished(self):
self.runButton.setDisabled(False)
self.stopButton.setDisabled(True)
@QtCore.pyqtSlot(object)
def onResultChanged(self, result):
print(result)
def initUI(self):
self.stopButton = QtWidgets.QPushButton("Stop")
self.stopButton.setDisabled(True)
self.runButton = QtWidgets.QPushButton("Run")
self.runButton.clicked.connect(self.start_event)
self.stopButton.clicked.connect(self.obj.stop_work)
hbox = QtWidgets.QHBoxLayout(self)
hbox.addWidget(self.runButton)
hbox.addWidget(self.stopButton)
self.show()
def closeEvent(self, event):
self.obj.stop_work()
super().closeEvent(event)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ex = Gui()
sys.exit(app.exec_())
答案 1 :(得分:0)
您可以将timeout
的{{1}}参数与multiprocessing.Queue
结合使用,以定期取消阻止执行和处理事件(例如异常):
time.sleep
在您的示例中,您可以将import time
import multiprocessing as mp
def run_event(params, queue):
time.sleep(10)
queue.put(params)
if __name__ == '__main__':
queue = mp.Queue()
process = mp.Process(target=run_event, args=('foo', queue))
process.start()
while True:
try:
result = queue.get(timeout=0.1)
except mp.queues.Empty:
pass
else:
break
print(result)
替换为while True
,然后在点击按钮时设置while not self._stop_execution
。