You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5结合多进程使用单个QProgressBar出现卡顿该如何修复

问题原因
  • 在Qt主线程中调用t.join()会直接阻塞主线程的Qt事件循环,所有UI更新、事件响应都会暂停,所以进度条无法实时刷新,只能等到子线程完全执行结束后才会一次性更新,看起来就是卡顿。
  • 原代码中multiprocessing.Pool的回调函数display是在你创建的子线程t中执行的,直接在非主线程操作Qt UI组件属于线程不安全操作,存在崩溃隐患。
修复方案

核心逻辑是不要阻塞主线程,用Qt的信号槽机制实现异步通知:

  • 进度更新、任务完成都通过信号从子线程发送到主线程,主线程收到信号后再操作UI、执行后续逻辑
  • 去掉主线程中的t.join()调用,后续基于results的操作放到任务完成信号的绑定槽函数中执行
修复后完整代码
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSignal
import multiprocessing as mp
import threading

targets = list(range(0, 100))


def process(i):
    print("target:", i)
    # 执行业务逻辑,示例如下:
    for c in range(1000):
        for r in range(1000):
            c = c * r + 4
    return i


class MainWin(QWidget):
    # 自定义信号:进度更新、任务完成
    progress_updated = pyqtSignal()
    task_finished = pyqtSignal(list)

    def __init__(self):
        super(MainWin, self).__init__()
        self.setupUi()
        # 绑定信号槽
        self.progress_updated.connect(self.display)
        self.task_finished.connect(self.on_task_finished)

    def setupUi(self):
        self.setFixedSize(500, 90)
        self.layout = QGridLayout()
        self.main_widget = QWidget(self)
        self.progressBar = QProgressBar()
        self.progressBar.setValue(0)

        self.btn = QPushButton('start')

        self.layout.addWidget(self.progressBar, 0, 0, 1, 1)
        self.layout.addWidget(self.btn, 1, 0, 1, 1)
        self.setLayout(self.layout)

        self.btn.clicked.connect(self.run)

    def display(self):
        self.progressBar.setValue(self.progressBar.value() + 1)
        print("process bar:", self.progressBar.value())

    def on_task_finished(self, results):
        # 所有任务完成后在这里执行后续基于results的操作
        print("所有任务处理完成,results长度:", len(results))
        # 你的后续逻辑写在这里

    def run(self):
        def func(results):
            pool = mp.Pool()
            for t in targets:
                # 回调函数改为发射进度更新信号
                pool.apply_async(process, (t,), callback=lambda x: self.progress_updated.emit())
                results.append(t)
            pool.close()
            pool.join()
            # 任务全部完成,发射完成信号,传递results
            self.task_finished.emit(results)

        results = []
        t = threading.Thread(target=func, args=(results,))
        t.start()
        # 不要在这里调用t.join()阻塞主线程


if __name__ == '__main__':
    app = QApplication(sys.argv)
    main_win = MainWin()
    main_win.show()
    sys.exit(app.exec_())

内容的提问来源于stack exchange,提问作者William Chan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 10:36:04