Python:如何将多进程链接到多进程条

时间:2014-03-11 21:11:54

标签: python pyqt multiprocessing

似乎我已经危险地接近能够将子处理的Pool()启动的所有子进程链接到PyQt Progress Bar小部件。这是示例代码。显然,很少有流动可以阻止我的梦想发生。

概念:

externalFunc()执行所有主要任务。它会不时发送其进度值'通过将VALUE存储到使用:

声明的poolDict变量中来实现MainWindow()实例
poolDict=manager.dict()

同时myEvenListener()方法在后台运行,等待VALUE发布'。一旦VALUE"收到" myEvenListener()将ProgressBar更新为收到的VALUE并将其重置为零(以避免重复的progressBar更新)。 在尝试更新ProgressBar之前,myEvenListener(self)验证ProgressBar在继续使用之前尚未达到其最大值100:

if pb.value()>=100: continue

不幸的是,即使externalFunc()提供了足够多的值(160),ProgressBar也不会达到100.除此之外,没有办法在循环时退出MainWindow()。

在阅读之前请小心运行此代码,因为它可能会在您的计算机上生成必须终止的多python进程。

问题:

  1. 为什么ProgressBar永远不会达到最高100
  2. 如何确保myEvenListener()方法在不需要时不运行。
  3. 如何确保所有子流程在之后死亡: 一个。所有进度条均为100% 湾用户关闭对话框或终止主进程。

  4. import sys, time
    from PyQt4 import QtCore, QtGui
    
    import multiprocessing as mp
    from multiprocessing import Pool
    manager = mp.Manager()
    
    poolDict=manager.dict()
    
    class PbWidget(QtGui.QProgressBar):
        def __init__(self, parent=None, total=20):
            super(PbWidget, self).__init__()
            self.setMinimum(1)
            self.setMaximum(total)        
            self._active = False  
    
        def update_bar(self, to_add_number):
            while True:
                time.sleep(0.01)
                value = self.value() + to_add_number            
                self.setValue(value)
                QtGui.qApp.processEvents()
                if (not self._active or value >= self.maximum()):                
                    break
            self._active = False
    
        def closeEvent(self, event):
            self._active = False
    
    
    def externalFunc(each):
        for i in range(16):
            print i
            poolDict[each]=10+i 
            time.sleep(0.5)
    
    
    class MainWindow(QtGui.QMainWindow):
        def __init__(self):
            super(MainWindow, self).__init__()
            # self.myList=[.1, .3, .5, 1.0, 1.5, 2.9, 3.1]
            self.myList=[1]
            self.main_layout = QtGui.QVBoxLayout()
            self.pBars={}
            self.state=True
    
            for each in self.myList:
                pb=PbWidget(total=101)
                self.main_layout.addWidget(pb)
                self.pBars[each]={'pb':pb, 'value':0, 'total_value':0} 
    
            ok_button = QtGui.QPushButton("OK")
            ok_button.clicked.connect(self.OK)      
            self.main_layout.addWidget(ok_button)       
    
            central_widget = QtGui.QWidget()
            central_widget.setLayout(self.main_layout)
            self.setCentralWidget(central_widget)
    
        def myEvenListener(self):
            """This function runs at the background as an infinite while loop. It constantly reads 
            a value stored in poolDict variable to which externalFunc() writes a new value every second. 
            The value represents a 'Progress' and needs to be passes to Progress Bar widget to which only MainWindow() 
            class has an access. After a Value was read it is used to update a Progress Bar. 
            After a progress bar was updated the Value is reset to zero. 
            The Problem: 'if pb.value()>=100' statement is used to make sure the function doesn't loop if the ProgressBar
            is already reached 100. By some reason the bar never reaches its maximum 100 even while externalFunc() calls
            enough times to reach this number. An ussue # 2: There is no meachanism to exit this while loop without adding
            three more variables... Can it be achieved with what we already have? 
            """
            while self.state:    
                for each in self.pBars:
                    pb = self.pBars[each]['pb']
                    print "\n Current Bar value =", pb.value()
                    if pb.value()>=100:
                        print 'skipping'
                        continue
    
                    value=None
                    if each in poolDict.keys(): 
                        # read delivered value
                        delivered_value=poolDict[each]
                        # reset delivered value
                        poolDict[each]=0
                        # update bar with delivered value
                        if ( 101-pb.value() ) < delivered_value:
                            print "\n\t UPDATING WITH "
                            pb.update_bar( 101-pb.value() )
                            print "\n\t AFTER ", pb.value()
                        else:
                            pb.update_bar( delivered_value )
                        # print '\n\t\t\t  Updating bar using this value', delivered_value
    
    
        def OK(self):
            pool = Pool(processes=3)
            pool.map_async( externalFunc, self.myList)
            self.myEvenListener()
    
    if __name__ == '__main__':
        app = QtGui.QApplication(sys.argv)
        window = MainWindow()
        window.resize(480, 320)
        window.show()
        sys.exit(app.exec_())
    

1 个答案:

答案 0 :(得分:2)

enter image description here

这是修改后的代码。它似乎运作良好,而且非常稳定。

import sys, time
from PyQt4 import QtCore, QtGui

import multiprocessing as mp
from multiprocessing import Pool
manager = mp.Manager()
poolDict=manager.dict()

class PbWidget(QtGui.QProgressBar):
    def __init__(self, parent=None, total=20):
        super(PbWidget, self).__init__()
        self.setMinimum(1)
        self.setMaximum(total)        
        self._active = False  

    def update_bar(self, to_add_number):
        while True:
            time.sleep(0.01)
            value = self.value() + to_add_number            
            self.setValue(value)
            QtGui.qApp.processEvents()
            if (not self._active or value >= self.maximum()):                
                break
        self._active = False

    def closeEvent(self, event):
        self._active = False


def externalFunc(each):
    for i in range(16):
        value =10+i
        poolDict[each]=value    
        time.sleep(each)


class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.myList=[.5, .8, 1.2, 1.8, 2.2, .3, .1]

        self.main_layout = QtGui.QVBoxLayout()
        self.pBars={}
        self.state=True
        self.name=None

        for each in self.myList:
            pb=PbWidget(total=101)
            self.main_layout.addWidget(pb)
            self.pBars[each]={'pb':pb, 'name':each} 

        ok_button = QtGui.QPushButton("Distribute")
        ok_button.clicked.connect(self.OK)      
        self.main_layout.addWidget(ok_button)       

        central_widget = QtGui.QWidget()
        central_widget.setLayout(self.main_layout)
        self.setCentralWidget(central_widget)

    def myEvenListener(self):
        """This function runs at the background as an infinite loop. It is constantly reading
        a value stored in poolDict variable to which externalFunc() writes a new value. 
        The value represents a 'Progress' and needs to be passed to Progress Bar widget to which MainWindow() 
        class has an access. After a Value was read and used to update a Progress Bar it is reset to zero.       
        """ 
        entities = self.pBars.keys()
        while self.state:    
            for each in entities:
                if each not in self.pBars.keys():   continue    

                pb = self.pBars[each]['pb']
                if pb.value()>=100:
                    self.pBars.pop(each, None)

                value=None
                if each in poolDict.keys():
                    # read delivered value
                    delivered_value=poolDict[each]
                    # reset delivered value
                    poolDict[each]=0
                    # update bar with delivered value
                    if ( 101-pb.value() ) < delivered_value:
                        pb.update_bar( 101-pb.value() )                     
                    elif delivered_value>0:
                        pb.update_bar( delivered_value )

                if len(self.pBars.keys())==0:
                    self.state=False

    def OK(self):       
        pool = Pool(processes=3)
        pool.map_async( externalFunc, self.myList)
        self.myEvenListener()

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    window = MainWindow()
    window.resize(480, 320)
    window.show()
    sys.exit(app.exec_())