2013-11-19 4 views
4

Я пытаюсь создать простое приложение с резьбой, в котором у меня есть метод, который выполняет некоторую длинную обработку и виджет, отображающий панель загрузки и кнопку отмены.pyqt QThread blocking main thread

Моя проблема заключается в том, что независимо от того, как я реализую потоки, на самом деле это не поток - пользовательский интерфейс блокируется после того, как поток начинает работать. Я прочитал каждый учебник и разместил об этом, и теперь я прибегаю к попросив сообщество попытаться решить мою проблему, поскольку я в недоумении!

Первоначально я пробовал подклассифицировать QThread, пока интернет не сказал, что это неправильно. Затем я попытался использовать метод moveToThread, но он сделал нулевую разницу.

Initialization Код:

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

PythonThread класс (по-видимому объектов QThread прослушиваются в 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 (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)) 

Любая помощь очень ценится!

Спасибо. Бен.

+0

Что такое именно «тяжелый подъем»? Ответ на этот вопрос может повлиять на то, будет ли нарезка ничем не отличаться (из-за ограничений, налагаемых GIL Python). – ekhumoro

+0

В основном это относится к SQL-запросам. Я не так заинтересован в производительности, как отзывчивый интерфейс. – Ben

+0

Я не говорил о производительности. Если GIL не будет выпущен во время долговременной задачи, тогда, _in себя_, потоки не будут препятствовать блокировке. Вам нужно разбить задачу на куски и периодически отправлять сигнал в основной поток графического интерфейса, чтобы он мог обрабатывать любые ожидающие события (т. Е. Вызывать 'qApp.processEvents() 'или что-то еще). – ekhumoro

ответ

1

проблема заключалась в использовании библиотеки SQL, которую я использовал (пользовательское внутреннее решение), которое оказалось небезопасным потоком и, таким образом, выполняло блокировку que Риз.

Если у вас возникли проблемы, попробуйте удалить SQL-запросы и посмотреть, все ли они блокируются. Если это решает проблему блокировки, попробуйте повторно ввести свои запросы с использованием необработанного SQL через MySQLdb (или эквивалент для используемого типа БД). Это будет диагностировать, есть ли проблема с вашим выбором библиотеки SQL.

0

Функция, связанная с сигналом started, будет запускать поток, который был подключен, основной поток графического интерфейса. Однако функция start() QThread выполняет свой метод run() в потоке после инициализации потока, поэтому необходимо создать подкласс QThread и запустить его метод запуска LoadThread.load - функцию, которую вы хотите выполнить. Не наследуйте от PythonThread, в этом нет необходимости. Для запуска потока следует использовать метод start() подкласса QThread.

PS: Так как в этом случае подкласс run() метода QThread только вызывает 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 

Пример:

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_() 
+0

Это был мой оригинальный подход, который также не работает. – Ben

+0

У меня похожие проблемы, вы когда-нибудь находили решение? – user2145312

+0

Привет @ user2145312, да - оказалось, что библиотека SQL, которую я использовал (собственное внутреннее решение), не была потокобезопасной и, следовательно, выполняла блокирующие запросы. Если ваша проблема также связана с SQL, сначала попробуйте удалить вызовы SQL и посмотреть, все ли она блокируется. Если это решает проблему блокировки, попробуйте повторно ввести свои запросы с помощью необработанного SQL через 'MySQLdb' (или эквивалент для используемого вами типа БД). Это будет диагностировать, есть ли проблема с вашим выбором библиотеки SQL. – Ben