[英]In PyQT how to store data emitted from signal in QRunnable
I have a process that takes awhile in a PyQT4 application using Python3. 我在使用Python3的PyQT4应用程序中花了一段时间。 So I have been investigating using threading to speed it up.
所以我一直在研究使用线程加速它。 The data can easily be broken part and processed in a loop.
数据很容易被破坏并循环处理。 I am using a custom
QRunnable
where you can pass a target function and args which is then fed into a QThreadpool
. 我正在使用自定义
QRunnable
,您可以在其中传递目标函数和args,然后将其馈送到QThreadpool
。 I use a pyqtSignal
to emit the processed data from each worker. 我使用
pyqtSignal
从每个工作程序中发出处理后的数据。 The Data is being received by my slot but it isn't being stored. 我的广告位正在接收数据,但未存储数据。 Below is an cut down example of what I have attempted.
以下是我尝试过的简化示例。
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_()
It runs and from the print outs the following: 它会运行,并且从打印输出中可以看到以下内容:
Crunching ... 0
Crunching ... 1
Crunching ... 3
Crunching ... 2
All done ... and the data is: []
Received ... 13
Received ... 11
Received ... 12
Received ... 10
Ok, so the signals aren't emitted until after they all finish? 好吧,信号要等到信号全部完成后才发出吗? maybe?
也许? or I can't assign to
_procData
since I am in a different thread or something? 还是因为我在不同的线程中或其他原因而无法分配给
_procData
? I tried removing the waitForDone()
just to see but that as expected didn't help. 我试图删除
waitForDone()
只是为了看看,但是按预期没有帮助。
So what is the proper way to assemble the data output from each worker? 那么,组装每个工人的数据输出的正确方法是什么? And I suppose a follow up question, how do you ensure it is put back in the correct order.
我想提出一个后续问题,即如何确保以正确的顺序放回原位。
I encountered a similar issue (which can also be related to this question : Emitting signals from a QRunnable ) with one of my code. 我的代码之一遇到了类似的问题(也可能与此问题有关: 从QRunnable发出信号 )。
As in your case, the action in the QRunnable
was executed but results weren't appended in the result list. 与您的情况一样,已执行
QRunnable
的操作,但结果未添加到结果列表中。 The answer in the other post says it's because the main event loop isn't called (with something like app.exec_()
). 在另一篇文章中的答案说这是因为没有调用主事件循环(使用
app.exec_()
类的东西)。 I guess in your case it's because you try to print the returned result (which is empty) before calling app.exec_()
(I might have read that events/signals from QThread or QRunnable are queued or something like that before the exec_
call ? Even if in your case as in mine, each individually result received could be printed from the callback function). 我想在您的情况下是因为您尝试在调用
app.exec_()
)之前打印返回的结果(为空)(我可能已经阅读了QThread或QRunnable的事件/信号已排队,或在exec_
调用之前进行了exec_
?即使在您的情况下,也可以从回调函数中打印接收到的每个结果。
I guess a work-around could be to create a QEventLoop
which will processEvents
from the worker of the QThreadPool
, then when it exit()
all signals/events have been processed. 我想一个变通可能是创建一个
QEventLoop
这将processEvents
从的工人QThreadPool
,那么当它exit()
所有信号/事件被处理。 Using your code it could look like : 使用您的代码可能看起来像:
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
(I did not tested this snippet of code but I successfully use a similar pattern for some of my QThreadPool
) (我没有测试此代码段,但是我对我的某些
QThreadPool
成功使用了类似的模式)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.