简体   繁体   English

在PyQT中如何将信号发射的数据存储在QRunnable中

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM