简体   繁体   English

pyqt QThread阻塞主线程

[英]pyqt QThread blocking main thread

I'm trying to create a simple threaded application whereby i have a method which does some long processing and a widget that displays a loading bar and cancel button. 我正在尝试创建一个简单的线程应用程序,我有一个方法,它做了一些长处理和一个显示加载栏和取消按钮的小部件。

My problem is that no matter how i implement the threading it doesn't actually thread - the UI is locked up once the thread kicks in. I've read every tutorial and post about this and i'm now resorting on asking the community to try and solve my problem as i'm at a loss! 我的问题是,无论我如何实现线程,它实际上都没有线程 - 一旦线程启动,UI就会被锁定。我已阅读每个教程并发布有关此内容的信息,我现在正在求助社区我试着解决我的问题,因为我不知所措!

Initially i tried subclassing QThread until the internet said this was wrong. 最初我尝试了继承QThread,直到互联网说这是错误的。 I then attempted the moveToThread approach but it made zero difference. 然后我尝试了moveToThread方法,但它没有区别。

Initialization code: 初始化代码:

loadingThreadObject = LoadThread(arg1)
loadingThread = PythonThread()
loadingThreadObject.moveToThread(loadingThread)
loadingThread.started.connect(loadingThreadObject.load)
loadingThread.start()

PythonThread class (apparently QThreads are bugged in pyQt and don't start unless you do this): PythonThread类(显然QThreads在pyQt中被窃听并且除非你这样做否则不启动):

class PythonThread (QtCore.QThread):
    def __init__(self, parent=None):
        QtCore.QThread.__init__(self, parent)

    def start(self):
        QtCore.QThread.start(self)

    def run(self):
        QtCore.QThread.run(self)

LoadThread class: LoadThread类:

class LoadThread (QtCore.QObject):
    results = QtCore.Signal(tuple)

    def __init__ (self, arg):
         # Init QObject
         super(QtCore.QObject, self).__init__()

         # Store the argument
         self.arg = arg

    def load (self):
         #
         # Some heavy lifting is done
         #

         loaded = True
         errors = []

         # Emits the results
         self.results.emit((loaded, errors))

Any help is greatly appreciated! 任何帮助是极大的赞赏!

Thanks. 谢谢。 Ben. 本。

The problem was with the SQL library I was using (a custom in-house solution) which turned out not to be thread safe and thus performed blocking queries. 问题在于我使用的SQL库(一个自定义的内部解决方案),结果证明它不是线程安全的,因此执行了阻塞查询。

If you are having a similar problem, first try removing the SQL calls and seeing if it still blocks. 如果您遇到类似问题,请首先尝试删除SQL调用并查看它是否仍然阻塞。 If that solves the blocking issue, try reintroducing your queries using raw SQL via MySQLdb (or the equivalent for the type of DB you're using). 如果这解决了阻塞问题,请尝试通过MySQLdb使用原始SQL重新引入查询(或者使用您正在使用的DB类型的等效项)。 This will diagnose whether or not the problem is with your choice of SQL library. 这将诊断问题是否与您选择的SQL库有关。

The function connected to the started signal will run the thread which it was connected, the main GUI thread. 连接到started信号的功能将运行它所连接的线程,即主GUI线程。 However, a QThread's start() function executes its run() method in the thread after the thread is initialized so a subclass of QThread should be created and its run method should run LoadThread.load , the function you want to execute. 但是,在初始化线程后,QThread的start()函数在线程中执行其run()方法,因此应创建QThread的子类,并且其run方法应运行LoadThread.load ,即要执行的函数。 Don't inherit from PythonThread, there's no need for that. 不要继承PythonThread,没有必要这样做。 The QThread subclass's start() method should be used to start the thread. 应该使用QThread子类的start()方法来启动线程。

PS : Since in this case the subclass of QThread's run() method only calls LoadThread.load() , the run() method could be simply set to LoadThread.load : PS :因为在这种情况下,QThread的run()方法的子类只调用LoadThread.load() ,所以run()方法可以简单地设置为LoadThread.load

class MyThread(QtCore.QThread):
    run = LoadThread.load # x = y in the class block sets the class's x variable to y

An example: 一个例子:

import time
from PyQt4 import QtCore, QtGui
import sys
application = QtGui.QApplication(sys.argv)

class LoadThread (QtCore.QObject):
    results = QtCore.pyqtSignal(tuple)

    def __init__ (self, arg):
         # Init QObject
         super(QtCore.QObject, self).__init__()

         # Store the argument
         self.arg = arg

    def load(self):
         #
         # Some heavy lifting is done
         #
         time.sleep(5)
         loaded = True
         errors = []

         # Emits the results
         self.results.emit((loaded, errors))

l = LoadThread("test")

class MyThread(QtCore.QThread):
    run = l.load

thread = MyThread()

button = QtGui.QPushButton("Do 5 virtual push-ups")
button.clicked.connect(thread.start)
button.show()
l.results.connect(lambda:button.setText("Phew! Push ups done"))
application.exec_()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM