如果子进程的任务耗时较长,并且在退出时仍在执行,那么在退出事件处理函数中等待子进程结束可能会导致界面卡顿。为了解决这个问题,可以使用一种异步的方式来处理子进程的终止。
一种常见的方法是使用信号量(Semaphore)来控制子进程的终止。通过引入一个信号量,我们可以在退出事件处理函数中发送一个信号给子进程,告知它应该尽快终止任务。子进程可以在适当的时候检查这个信号,并在接收到信号后尽快终止任务。
以下是修改后的代码示例:
?其中退出进程线程的部分需要修改一下。
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QMessageBox
from multiprocessing import Process, Queue
import threading
import time
import sys
from multiprocessing import Semaphore
class MyProcess(Process):
def __init__(self, q, data, semaphore):
super().__init__()
self.q = q
self.data = data
self.semaphore = semaphore
def run(self):
time.sleep(20)
# 检查信号量,如果接收到信号则终止任务
if self.semaphore.acquire(blocking=False):
print('接收到终止信号,子进程终止任务')
return
print('子进程开始put数据')
self.data.append('123')
self.q.put(self.data)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.q = Queue()
self.data = ['111', '222', '333'] # 要传递的列表
self.semaphore = Semaphore(0) # 初始化信号量
self.button = QPushButton('启动子进程', self)
self.button.clicked.connect(self.start_child_process)
def start_child_process(self):
def run_child_process():
p = MyProcess(self.q, self.data, self.semaphore)
p.start()
p.join()
# 子进程完成后的逻辑
result = self.q.get()
print('主进程获取Queue数据:', result)
self.thread = threading.Thread(target=run_child_process)
self.thread.start()
def closeEvent(self, event):
reply = QMessageBox.question(self, '退出确认', '确定要退出吗?',
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
if reply == QMessageBox.Yes:
# 发送终止信号给子进程
self.semaphore.release()
event.accept()
else:
event.ignore()
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
window.show()
sys.exit(app.exec_())
我们引入了一个Semaphore
对象semaphore
,用于控制子进程的终止。在子进程的run
方法中,首先检查信号量是否被获取(即是否接收到终止信号),如果是,则终止任务并返回。这样可以确保子进程在接收到终止信号后尽快终止任务。
在退出事件处理函数closeEvent
中,我们调用self.semaphore.release()
发送终止信号给子进程。然后,我们接受退出事件(调用event.accept()
),这样应用程序会终止。
通过这样的处理,当用户点击关闭按钮时,会发送终止信号给子进程,子进程在适当的时候终止任务,从而避免了界面卡顿的问题。