我试图做一个相当普遍的事情在我的PySide GUI应用程序:我要委托一些CPU密集型任务的后台线程,使我的GUI保持敏感,并为云计算甚至可以显示一个进度指示器。
下面是我在做什么(我使用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()
该应用程序显示的一个按钮的单个窗口。 当按下按钮,我希望在执行计算它禁用本身。 那么,应该重新启用按钮。
会发生什么,取而代之的,是当我按下按钮整个窗口冻结而计算云,然后,它结束时,我重新获得应用程序的控制。 按钮似乎从来没有被禁用。 我注意到一个有趣的事情是,如果我替换CPU密集型计算do_stuff()
用一个简单的time.sleep()程序行为与预期相同。
我不知道到底发生了什么事情,但现在看来,第二个线程的优先级是如此之高,它实际上是防止以往任何时候都被调度的GUI线程。 如果第二个线程进入受阻状态(因为它有一个发生sleep()
图形用户界面实际上已经运行的机会,如预期更新的接口。 我试图改变工作线程的优先级,但它看起来像它不能在Linux上完成。
另外,我尝试打印线程ID,但我不知道如果我做正确。 如果我的线程关联性似乎是正确的。
我也试过用程序和PyQt的行为是完全一样的,因此,标签和标题。 如果我可以把它与PyQt4的,而不是PySide来看,我可以转我的整个应用程序PyQt4的