我有一个使用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}}只是为了看到,但正如预期的那样没有帮助。
那么从每个工作人员组装数据输出的正确方法是什么?我想一个跟进问题,你如何确保它按正确的顺序放回来。
答案 0 :(得分:1)
我遇到了一个类似的问题(也可能与此问题有关:Emitting signals from a QRunnable)和我的代码之一。
与您的情况一样,QRunnable
中的操作已执行,但结果未附加到结果列表中。另一篇文章中的答案说它是因为没有调用主事件循环(类似于app.exec_()
)。我猜你的情况是因为你在调用app.exec_()
之前尝试打印返回的结果(它是空的)(我可能已经读过来自QThread或QRunnable的事件/信号排队等等之前exec_
调用?即使在你的情况下,也可以从回调函数中打印出收到的每个单独结果。
我想解决方法可能是创建一个QEventLoop
,processEvents
来自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
使用了类似的模式)