在PyQT中如何存储从QRunnable中的信号发出的数据

时间:2015-08-06 00:01:55

标签: python qt pyqt

我有一个使用Python3在PyQT4应用程序中需要一段时间的过程。所以我一直在研究使用线程加速它。数据很容易被破坏并循环处理。我正在使用自定义QThreadpool,您可以在其中传递目标函数和args,然后将其输入pyqtSignal。我使用import sys, time from random import uniform from PyQt4 import QtCore, QtGui class AWorker(QtCore.QRunnable): """ Generic Task for ThreadPool to execute required Kwargs = target (<function>): function to call args (tuple): args for target kwargs (dict): kwargs for target """ def __init__(self, target=None, args=(), kwargs={}): super(AWorker, self).__init__() self.target = target self.args = args self.kwargs = kwargs def run(self): self.target(*self.args, **self.kwargs) class myTest(QtCore.QObject): doneSignal = QtCore.pyqtSignal(int) #Create a signal to emit the data def __init__(self): super(myTest, self).__init__() self._procData = [] #Place to Store data .. maybe self.pool = QtCore.QThreadPool.globalInstance() self.pool.setMaxThreadCount(4) #Use up to 8 threads def runAll(self): self.doneSignal.connect(self.storeData) for data in range(4): worker = AWorker(target=self.processData, args=(data,)) self.pool.start(worker) def processData(self,data): print('Crunching ...', str(data)) outData = data+10 time.sleep(uniform(1,3)) #Simulate this taking a random amount of time self.doneSignal.emit(outData) def storeData(self,data): print('Received ...', str(data)) self._procData.append(data) def getData(self): return self._procData if __name__ == '__main__': app = QtGui.QApplication(sys.argv) test = myTest() test.runAll() test.pool.waitForDone() print('All done ... and the data is: ',test.getData()) app.exec_() 从每个worker发出处理过的数据。我的插槽正在接收数据,但它没有被存储。以下是我尝试过的一个简要示例。

Crunching ... 0
Crunching ... 1
Crunching ... 3
Crunching ... 2
All done ... and the data is:  []
Received ... 13
Received ... 11
Received ... 12
Received ... 10

它从以下打印输出:

_procData

好的,所以信号在它们全部完成之后才会发出?也许?或者我不能分配给waitForDone(),因为我处于不同的线索或其他什么?我尝试删除{{1}}只是为了看到,但正如预期的那样没有帮助。

那么从每个工作人员组装数据输出的正确方法是什么?我想一个跟进问题,你如何确保它按正确的顺序放回来。

1 个答案:

答案 0 :(得分:1)

我遇到了一个类似的问题(也可能与此问题有关:Emitting signals from a QRunnable)和我的代码之一。
与您的情况一样,QRunnable中的操作已执行,但结果未附加到结果列表中。另一篇文章中的答案说它是因为没有调用主事件循环(类似于app.exec_())。我猜你的情况是因为你在调用app.exec_()之前尝试打印返回的结果(它是空的)(我可能已经读过来自QThread或QRunnable的事件/信号排队等等之前exec_调用?即使在你的情况下,也可以从回调函数中打印出收到的每个单独结果。

我想解决方法可能是创建一个QEventLoopprocessEvents来自QThreadPool的工作人员,然后当exit()所有信号/事件都有已被处理。使用您的代码可能看起来像:

def runAll(self):
    self.eventloop = QEventLoop()
    self.pool = QtCore.QThreadPool.globalInstance()
    self.pool.setMaxThreadCount(4)
    self.doneSignal.connect(self.storeData) 
    for data in range(4):
        worker = AWorker(target=self.processData, args=(data,))
        self.pool.start(worker)
    self.pool.waitForDone()
    self.eventloop.processEvents() 
    self.eventloop.exit()
    # Now your data should have been appended to your list 

(我没有测试过这段代码但是我成功地为我的QThreadPool使用了类似的模式)