【问题标题】:In PyQT how to store data emitted from signal in QRunnable在 PyQT 中,如何将信号发出的数据存储在 QRunnable 中
【发布时间】:2016-02-06 02:35:08
【问题描述】:

我有一个使用 Python3 的 PyQT4 应用程序需要一段时间的过程。所以我一直在研究使用线程来加速它。数据很容易被破坏部分并在循环中处理。我正在使用自定义QRunnable,您可以在其中传递目标函数和参数,然后将其输入QThreadpool。我使用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_()

它运行并从打印输出如下:

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

好的,所以直到信号都完成后才会发出信号?也许?或者我不能分配给_procData,因为我在不同的线程或什么的?我尝试删除 waitForDone() 只是为了看看,但正如预期的那样没有帮助。

那么,组装每个工人的数据输出的正确方法是什么?我想一个后续问题,你如何确保它以正确的顺序放回。

【问题讨论】:

  • 在我看来 QThreadPool.waitForDone 实际上并没有等待。全部完成后,您可以看到收到的正在打印。此外,如果您在每个storeData 调用中打印出_procData,您可以看到它实际上是在存储数据。例如Received ... 10 [13, 11, 12, 10]
  • 我明白你的意思。但是,我仍然不确定 waitForDone 是否不起作用,或者它是否阻塞了信号,直到等待完成完成。任何一个都会给出我认为的相同行为。如果您注释掉等待完成行,您会​​得到不同的打印输出顺序,其中一些“已接收”与“紧缩”混合,但“全部完成”行仍然是空白的。如果 waitForDone 没有做任何事情,那么无论哪种方式我都希望得到相同的输出。

标签: python qt pyqt


【解决方案1】:

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

我想解决方法可能是从QThreadPool 的工作人员创建一个QEventLoop processEvents,然后当它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 

(我没有测试这个 sn-p 的代码,但我成功地为我的一些 QThreadPool 使用了类似的模式)

【讨论】:

    猜你喜欢
    • 2016-09-18
    • 2012-11-26
    • 2021-12-17
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 2013-07-01
    • 2017-10-13
    相关资源
    最近更新 更多