PyQT5 多线程问题

Posted

技术标签:

【中文标题】PyQT5 多线程问题【英文标题】:PyQT5 Multi Thread Issue 【发布时间】:2021-03-28 08:36:14 【问题描述】:

我正在尝试使用 PYQT5 和 Qthread 运行多线程

我有两个与线程关联的按钮(进度条和一个操作等待 1 秒,然后打印“完成”),它们在同一个类中声明时运行良好。

我确实有第三个按钮,我链接到另一个类中插入的操作。这使我的程序在没有任何日志消息的情况下崩溃。真正让程序崩溃的是“self.thread2.start()”这行代码。

我不明白为什么这不起作用!你能帮我理解这个问题吗?

提前致谢

import sys
from PyQt5.QtCore  import *
from thread_progressbar import *
from Test_MT import *


class SimulationUi(QtWidgets.QDialog):
    def __init__(self):
        super(SimulationUi, self).__init__()
        self.btnStart = QtWidgets.QPushButton('Start')
        self.btnStart2 = QtWidgets.QPushButton('Start')
        self.btnStop = QtWidgets.QPushButton('Stop')
        self.btnStop2 = QtWidgets.QPushButton('Stop')
        self.btnQuit = QtWidgets.QPushButton('Quit')

        self.myprogressbar = QtWidgets.QProgressBar()
        self.myprogressbar2 = QtWidgets.QProgressBar()

        self.grid = QtWidgets.QGridLayout()
        self.grid.setSpacing(10)
        self.grid.addWidget(self.btnStart,1,0)
        self.grid.addWidget(self.btnStop,1,1)
        self.grid.addWidget(self.myprogressbar,2,0,1,3)
        self.grid.addWidget(self.btnStart2, 3, 0)
        self.grid.addWidget(self.btnStop2, 3, 1)
        self.setLayout(self.grid)

        # ------------------------
        #MULTI-THREAD MANAGEMENT
        #------------------------
        self.thread = QThread()
        self.thread.start()
        self.worker = thread_progressbar()
        self.worker.moveToThread(self.thread)
        self.worker.setValue.connect(self.myprogressbar.setValue)
        self.btnStart.clicked.connect(self.worker.startpgbar)
        self.btnStop.clicked.connect(lambda: self.worker.stoppgbar())

        class_tst = MakeList()
        class_tst.define_thread(self.btnStart2)

        self.thread3 = QThread()
        self.thread3.start()
        self.worker3 = Test()
        self.worker3.moveToThread( self.thread3 )
        self.btnStop2.clicked.connect( self.worker3.MT )


    def stop_thread(self):
        self.worker.stop()
        self.thread.quit()
        self.thread.wait()

    def quit_application(self):
        self.close()


class MakeList():
    def __init__(self):
        super(MakeList, self).__init__()
    def define_thread(self, MyObject):
        self.thread2 = QThread()
        self.thread2.start()
        self.worker2 = Test()
        self.worker2.moveToThread(self.thread2 )
        MyObject.clicked.connect( self.worker2.MT )


if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv)
    simul = SimulationUi()
    simul.show()
    sys.exit(app.exec_())

Test_MT 文件
import os, time
from PyQt5 import QtCore


class Test(QtCore.QObject):
    def MT(self):
        time.sleep(1)
        print("done")

【问题讨论】:

很难真正区分,因为您的代码缺少某些部分(例如,thread_progressbar 在哪里?)并且通常有点混乱(您将对象移动到已经开始,你的命名并不是很冗长和一致)。也就是说,没有minimal, reproducible example,我们只能猜测。我的猜测是Makelist 是一个局部变量并且超出了范围,这会导致由于线程在运行时被破坏而导致崩溃。但是,如前所述,这只是一个猜测。提供 MRE。 【参考方案1】:

由于在SimulationUi.__init__ 中对MakeList 实例的唯一引用是局部变量class_tst,因此当SimulationUi.__init__ 返回时,该对象及其属性将被垃圾回收。由于其属性之一是正在运行的线程 (class_tst.thread2),这会导致程序崩溃。解决这个问题的最简单方法是通过将MakeList 对象分配给SimulationUi 的实例变量而不是局部变量(即在SimulationUi.__init__ 中使用self.class_tst = MakeList() 而不是class_tst=MakeList())来持久引用MakeList

【讨论】:

你在现场!这对我理解它的整体工作方式有很大帮助!

以上是关于PyQT5 多线程问题的主要内容,如果未能解决你的问题,请参考以下文章

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题

PyQt5中多线程模块QThread解决界面卡顿无响应问题,线程池ThreadPoolExecutor解决多任务耗时操作问题

PyQt5创建多线程

急急急 pyqt5 matplotlib 多线程问题,求大佬指点啊

Python3.5+PyQt5多线程+itchat实现微信防撤回桌面版代码