PySide/PyQt -Запуск потока с интенсивным использованием ЦП приводит к зависанию всего приложения

Я пытаюсь сделать довольно обычную вещь в своем приложении с графическим интерфейсом PySide :Я хочу делегировать часть процессора -Интенсивная задача фоновому потоку, чтобы мой графический интерфейс оставался отзывчивым и мог даже отображать индикатор выполнения по мере выполнения вычислений..

Вот что я делаю (Я использую PySide 1.1.1 на Python 2.7, Linux x86 _64):

import sys
import time
from PySide.QtGui import QMainWindow, QPushButton, QApplication, QWidget
from PySide.QtCore import QThread, QObject, Signal, Slot

class Worker(QObject):
    done_signal = Signal()

    def __init__(self, parent = None):
        QObject.__init__(self, parent)

    @Slot()
    def do_stuff(self):
        print "[thread %x] computation started" % self.thread().currentThreadId()
        for i in range(30):
            # time.sleep(0.2)
            x = 1000000
            y = 100**x
        print "[thread %x] computation ended" % self.thread().currentThreadId()
        self.done_signal.emit()


class Example(QWidget):

    def __init__(self):
        super(Example, self).__init__()

        self.initUI()

        self.work_thread = QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.work_thread)
        self.work_thread.started.connect(self.worker.do_stuff)
        self.worker.done_signal.connect(self.work_done)

    def initUI(self):

        self.btn = QPushButton('Do stuff', self)
        self.btn.resize(self.btn.sizeHint())
        self.btn.move(50, 50)       
        self.btn.clicked.connect(self.execute_thread)

        self.setGeometry(300, 300, 250, 150)
        self.setWindowTitle('Test')    
        self.show()


    def execute_thread(self):
        self.btn.setEnabled(False)
        self.btn.setText('Waiting...')
        self.work_thread.start()
        print "[main %x] started" % (self.thread().currentThreadId())

    def work_done(self):
        self.btn.setText('Do stuff')
        self.btn.setEnabled(True)
        self.work_thread.exit()
        print "[main %x] ended" % (self.thread().currentThreadId())


def main():

    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Приложение отображает одно окно с кнопкой. Когда кнопка нажата, я ожидаю, что она отключится во время выполнения вычисления. Затем кнопка должна снова -активироваться.

Вместо этого происходит то, что когда я нажимаю кнопку, все окно зависает, пока идет вычисление, а затем, когда оно завершено, я восстанавливаю контроль над приложением. Кнопка никогда не кажется отключенной. Забавная вещь, которую я заметил, заключается в том, что если я заменю интенсивные вычисления ЦП в do_stuff()простым time.sleep (), программа будет вести себя так, как ожидалось.

Я точно не знаю, что происходит,но похоже, что приоритет второго потока настолько высок, что фактически предотвращает планирование потока GUI. Если второй поток переходит в состояние BLOCKED (, как это происходит сsleep()), графический интерфейс действительно может работать и обновлять интерфейс, как и ожидалось. Я попытался изменить приоритет рабочего потока, но похоже, что это невозможно сделать в Linux.

Кроме того, я пытаюсь распечатать идентификаторы потоков, но не уверен, что делаю это правильно. Если да, то сходство потоков кажется правильным.

Я также попробовал программу с PyQt, и поведение точно такое же, отсюда и теги и заголовок. Если бы я мог заставить его работать с PyQt4 вместо PySide, я мог бы переключить все свое приложение на PyQt4

13
задан user1491306 29 June 2012 в 16:58
поделиться