QThread Windows无响应

时间:2017-10-10 07:03:36

标签: python multithreading pyqt qthread

我在Windows上的PyQt中编写了一个GUI程序。我的程序中有一些昂贵的操作。当这些操作正在运行时,程序在程序栏中显示“Not Responding”。

我认为必须将此操作块作为更新UI的主线程,所以我通过QThread编写多线程代码来测试它,它仍然没有意义。

我写了一个小程序来测试它,操作根本没有在新线程中运行,这是我的小测试代码:

from PyQt5.QtCore import QThread, QObject, QCoreApplication, qDebug, QTimer


class Worker(QObject):
    def on_timeout(self):
        qDebug('Worker.on_timeout get called from: %s' % hex(int(QThread.currentThreadId())))


if __name__ == '__main__':
    import sys

    app = QCoreApplication(sys.argv)
    qDebug('From main thread: %s' % hex(int(QThread.currentThreadId())))
    t = QThread()
    qDebug(t)
    worker = Worker()
    timer = QTimer()
    timer.timeout.connect(worker.on_timeout)
    timer.start(1000)
    timer.moveToThread(t)
    worker.moveToThread(t)
    t.start()

    app.exec_()

这是输出:

From main thread: 0x634
Worker.on_timeout get called from: 0x634

1 个答案:

答案 0 :(得分:0)

您的程序有多个错误,并且不会产生您显示的输出。

首先,无法将线程对象传递给qDebug - 参数必须是字符串。如果您想打印对象,请使用qDebug(repr(obj)) - 甚至更好,只需使用print(obj)

其次,您无法在创建它的线程之外启动计时器。您的示例在主线程中进行信号连接,并在主线程中启动计时器。所以worker.on_timeout将在主线程中调用。但是如果在将其移动到工作线程后连接并启动计时器,则会出现此错误:

  

QObject :: startTimer:定时器只能用于以...开头的线程   的QThread

我认为使用计时器是不必要的,并且会混淆您的示例,因此最好完全不使用它。相反,您应该将工作线程的started信号连接到工作对象的run方法。要模拟长时间运行的操作,可以使用QThread.sleep()

from PyQt5.QtCore import QThread, QObject, QCoreApplication

class Worker(QObject):
    def run(self):
        print('Worker called from: %#x' % int(QThread.currentThreadId()))
        QThread.sleep(2)
        print('Finished')
        QCoreApplication.quit()

if __name__ == '__main__':

    import sys
    app = QCoreApplication(sys.argv)
    print('From main thread: %#x' % int(QThread.currentThreadId()))
    t = QThread()
    worker = Worker()
    worker.moveToThread(t)
    t.started.connect(worker.run)
    t.start()
    app.exec_()

最后,请注意,在将一个worker对象移动到一个线程之后,你应该总是进行信号连接this answer中解释了原因。