为什么不要使用QThread


类型:Python,C++ & Qt4,创建时间:Jan. 6, 2015, 5:08 p.m.

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/97/。

之前我在Python中使用线程的技巧一文中提到,尽量不要在 PyQt 里面使用QThread,但是当时没有给出示例程序。这里补上一个会引起Python崩溃的代码。其实主要原因是QThread被强制关闭的时候会引起Python崩溃。

from __future__ import unicode_literals
from __future__ import print_function

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class Worker(QObject):
    @pyqtSlot()
    def doSomething(self):
        i = 0
        while True:
            i += 1
            t = i * 23729378 + 9273947297123123124

class MainWindow(QPushButton):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.setText("click me again and again.")
        self.clicked.connect(self.startNewThread)
        self.workers = []

    def startNewThread(self, checked):
        self.thread = QThread()
        worker = Worker()
        worker.moveToThread(self.thread)
        self.workers.append(worker)
        self.thread.start()
        QTimer.singleShot(0, worker, SLOT("doSomething()"))

def test():
    app = QApplication([])
    w = MainWindow()
    w.show()
    try:
        return app.exec_()
    except AttributeError:
        return getattr(app, "exec")()

if __name__ == "__main__":
    test()

使劲点击按钮,这段代码就会不断打印出QThread: Destroyed while thread is still running。通常情况下,Python会报一个段错误,然后退出。不过,经过测试,并非所有的PyQt版本都会立即异常报错。老鱼在使用 PyQt 4.11.1 + Python 2.7.8 (openSUSE) 的时候点击十几次就报错退出了。在 Windows 里面,即使没有Worker,把startNewThread()写成这样子,点击两三次也会异常退出:

def startNewThread(self, checked):
    self.thread = QThread()
    self.thread.start()

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/97/。


叁拾掃地肆拾不獲(Jan. 6, 2015, 8:10 p.m.)

不是QThread 不可用,而是博主用错了。

老鱼(Jan. 7, 2015, 11:35 a.m.)

QThread的正确用法就是如此。如果非要写QThread(self)的话,你就必须再写一个QThread::deleteLater(),不然内存泄露。

叁拾掃地肆拾不獲(Jan. 7, 2015, 11:52 a.m.)

不用 deleteLater,而应该把 self.thread = QThread() 移到 init 中,这只因为每次创建一个新的qthread,旧 qthread 被 gc 掉的缘故。

Louis(Nov. 12, 2018, 3:42 a.m.)

Good


何不来发表一下您对本文的看法(使用Markdown语法,分段空两行):