为啥在 macOS 上使用 QThread 时 PyQt 应用程序崩溃或挂起?

Posted

技术标签:

【中文标题】为啥在 macOS 上使用 QThread 时 PyQt 应用程序崩溃或挂起?【英文标题】:Why does PyQt application crash or hang when using QThread on macOS?为什么在 macOS 上使用 QThread 时 PyQt 应用程序崩溃或挂起? 【发布时间】:2020-11-18 23:55:03 【问题描述】:

在 PyQt5 中调用线程类时,应用程序崩溃并出现错误:QThread: Destroyed while thread is still running 如果我不添加

def __del__(self): 
     self.wait()

将上述语句添加到线程类后,应用程序运行但停止,直到线程完成执行(基本上使线程无用)。我正在运行 macOS Catalina 10.15.6、Intel i9、Python 3.7.4。有什么办法可以解决这个问题?代码如下(ui窗口只有一个按钮):

from PyQt5.QtWidgets import QMainWindow
from PyQt5 import QtWidgets, uic
from PyQt5.QtCore import QThread, pyqtSignal
import sys, time

class Main(QMainWindow):
    def __init__(self, parent=None):
        super(Main, self).__init__(parent)
        uic.loadUi('main.ui', self)
        self.btn1.clicked.connect(self.run_worker)

    def run_worker(self):
        worker = Worker_thread()
        worker.start()


class Worker_thread(QThread):
    def __init__(self):
        QThread.__init__(self)

    def __del__(self):
         self.wait()

    def run(self):
        time.sleep(10)


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

【问题讨论】:

__del__ 中添加self.wait() 是一个非常糟糕的主意。 @musicamante 能否详细说明原因? 有多种原因,包括您的情况(整个过程被阻塞直到完成,这意味着您可能需要杀死应用程序才能真正退出它,并且这不好)。此外,__del__ 甚至可能根本不会被调用,清理这样的异步资源是不安全的,并且可能会在 C++ 对象已被销毁的情况下对 python 引用进行垃圾收集。阅读somerelevantquestions。 【参考方案1】:

问题很简单:“worker”变量是一个局部变量,当它的作用域结束时它会被消除,在这种情况下,作用域是“run_worker”函数。当“run”方法被淘汰时,它不是在管理QThread的辅助线程中执行,而是在阻塞GUI的主线程中执行。

解决方法是扩展其范围,例如通过制作类属性:

def run_worker(self):
    self.worker = Worker_thread()
    self.worker.start()

注意:问题与操作系统无关。

【讨论】:

以上是关于为啥在 macOS 上使用 QThread 时 PyQt 应用程序崩溃或挂起?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 ASP.NET-Core 应用程序会收到错误消息“此平台不支持锁定/解锁文件区域”。在 MacOS 上部署时?

为啥我不能在类的成员函数中初始化 QThread?

为啥我的 QThread 正在使主线程挨饿?

为啥qthread永远不会退出?

为啥 Net-SSLeay 停止通过 GitHub 工作流程在 macOS 上安装?

我不确定为啥我的 QThread 模式会阻塞