Python 在 PyQt5 应用程序中因 2 个工作线程而崩溃

标签 python multithreading python-3.x pyqt5

我想在我的应用程序中有 2 个工作线程。一个应该在 GUI 加载后立即开始运行,另一个应该稍后通过某个信号启动。假设这是一次按钮点击。

当我的 Python 解释器在执行第二个线程时崩溃(如显示 Windows 错误“Python 停止工作”,没有堆栈跟踪)时,我遇到了奇怪的行为。

这是一个示例,单击按钮后就会崩溃。

class Worker(QtCore.QThread):
    def __init__(self, method_to_run):
        super().__init__()
        self.method = method_to_run

    def run(self):
        self.method()

class Window(QWidget):
    def __init__(self):
        super(Window, self).__init__()
        self.button = QPushButton('Test', self)
        self.label = QLabel(self)
        self.button.clicked.connect(self.handleButton)
        layout = QVBoxLayout(self)
        layout.addWidget(self.label)
        layout.addWidget(self.button)
        self.worker = Worker(self.test_method)
        self.worker.start()

    def handleButton(self):
        self.label.setText('Button Clicked!')
        worker = Worker(self.test_method)
        worker.start() 

    @staticmethod
    def test_method():
        res = [i*i for i in range(100500)]

if __name__ == '__main__':

    import sys
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

更奇怪的是,当您出于某种原因调试应用程序时,它不会崩溃。

我在这里缺少什么?

编辑 我可以从故障转储中获得很多信息,因为我没有 QT 的符号。但看起来崩溃发生在 QtCore.dll 内部

ExceptionAddress: 00000000632d4669 (Qt5Core!QThread::start+0x0000000000000229)

最佳答案

问题是您没有保存对线程的引用,因此一旦退出handleButton,它就会被删除。如果您保存引用,这就引出了如何处理其生命周期的问题。

QThread 不仅仅是系统线程的包装器 - 它还实现了其他服务,使您可以将线程连接到 GUI 中。您可以使用其 finished 处理程序在小部件终止执行任何清理操作时向其发出信号。

在此示例中,我将工作线程保存为 self.worker2 并阻止第二次启动工作线程,直到第一次完成为止。

import PyQt5
import PyQt5.QtCore as QtCore
from PyQt5.QtWidgets import *
import time

class Worker(QtCore.QThread):
    def __init__(self, method_to_run):
        super(Worker, self).__init__()
        self.method = method_to_run

    def run(self):
        self.method()

class Window(QWidget):
    def __init__(self):
        super().__init__()
        self.button = QPushButton('Test', self)
        self.label = QLabel(self)
        self.button.clicked.connect(self.handleButton)
        layout = QVBoxLayout(self)
        layout.addWidget(self.label)
        layout.addWidget(self.button)
        self.worker = Worker(self.test_method)
        self.worker.start()
        self.worker2 = None

    def handleButton(self):
        self.label.setText('Button Clicked!')
        # likely better to disable the button instead... but
        # this shows events in action.
        if self.worker2:
            self.label.setText('Worker already running')
        else:
            self.worker2 = Worker(self.test_method)
            self.worker2.finished.connect(self.handle_worker2_done)
            self.worker2.start() 

    def handle_worker2_done(self):
        self.worker2 = None
        self.label.setText('Worker done')

    @staticmethod
    def test_method():
        #res = [i*i for i in range(100500)]
        time.sleep(3)

if __name__ == '__main__':

    import sys
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

关于Python 在 PyQt5 应用程序中因 2 个工作线程而崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43188123/

相关文章:

python - 我可以使用 'function' 类创建函数吗?

python - 有没有办法使用 SWIG C++ 创建一个可以在 Python2 和 Python3 中导入的 python 模块

python - 如何在 Selenium 元素可用时立即访问它们,而不是等待整个页面加载

python - 使用 rebuild_index 的 Django Haystack 和 Elasticsearch 错误

vb.net - 多线程同时动态启动所有线程

c# - 在 HashSet<T> 中是否包含线程安全

python - Pandas DataFrame,计算距下一个指定日期还剩多少天?

python - 在Python中比较两个元组的部分值

python - 如何从 django 框架中的表单字段中获取值(value)?

c# - 多个作者,一个读者,哪个集合