multiprocessing.Queue不能在类中用作实例变量吗?

时间:2018-12-02 08:54:47

标签: python class queue multiprocessing

我想将多处理任务封装到一个类中。控制和辅助功能都是该类的成员。使用Pool.map_async()运行工作程序,因此可以在其他工作程序仍在运行时处理结果。处理结果存储在multiprocessing.Queue中。当Queue是实例变量时,它不起作用,而全局变量或类变量,则它起作用。

示例:

import multiprocessing 
class A():
    # Queue as instance variable
    def __init__(self):
        self.qout = multiprocessing.Queue()
    def worker(self,x):
        self.qout.put(x*x)   
    def process(self):
        values = range(10)
        with multiprocessing.Pool() as pool:
            res = pool.map_async(self.worker,values)        
            while (not self.qout.empty() or
                not res.ready()):
                val = self.qout.get()
                print(val)

qoutB = multiprocessing.Queue()
class B():
    # Queue as global variable
    def __init__(self):
        pass   
    def worker(self,x):
        qoutB.put(x*x)       
    def process(self):
        values = range(10)       
        with multiprocessing.Pool() as pool:
            res = pool.map_async(self.worker,values)           
            while (not qoutB.empty() or
                not res.ready()):
                val = qoutB.get()
                print(val)

class C():
    # Queue as Class variable
    qout = multiprocessing.Queue()
    def __init__(self):
        pass
    def worker(self,x):
        self.qout.put(x*x)   
    def process(self):
        values = range(10)
        with multiprocessing.Pool() as pool:
            res = pool.map_async(self.worker,values)        
            while (not self.qout.empty() or
                not res.ready()):
                val = self.qout.get()
                print(val)  

现在,当您按如下方式调用类时(将其放在类定义下面)

a=A()
a.process()

不起作用(可能停止等待self.qout.get(),但是

a=B()
a.process()

a=C()
a.process()

有效(打印结果)。为什么?

我在Python documentation中找不到任何相关信息。我没有尝试将队列作为参数传递,但这是应该对用户隐藏的功能。

B选项应该毫无疑问,C并不理想,因为队列将在该类的所有实例之间共享。

注意:已在Linux(Debian,来自存储库的Python 3.5)上进行了测试。

3 个答案:

答案 0 :(得分:0)

不是答案。我发布它是因为它是完整的,可运行的,并且显示了我过去得出的结论,即您的类没有一个是“有效的”,实际上,类A是唯一的类其while循环完成(尽管不打印任何内容),而在类BC中,它永远不会结束。

还要注意,我知道由于这三个类的通用性,它们都可能是某个基类的子类-但这不是这个问题的主题(这就是为什么有这么多冗余代码的原因)。

无论如何,对于您的问题,这样的事情会被认为是MCVE-如果只有它产生的结果与您所声称的相吻合,就是这样。

import multiprocessing

TEST_CLASS_NAME = 'B'  # Change as necessary.


if TEST_CLASS_NAME == 'A':

    class A():
        # Queue as instance variable
        def __init__(self):
            self.qout = multiprocessing.Queue()

        def worker(self, x):
            self.qout.put(x*x)

        def process(self):
            values = range(10)
            with multiprocessing.Pool() as pool:
                res = pool.map_async(self.worker, values)
                classname = type(self).__name__
                print(classname, '- while loop starting')
                while not self.qout.empty() or not res.ready():
                    val = self.qout.get()
                    print(val)
                print(classname, '- while loop ended')


elif TEST_CLASS_NAME == 'B':

    qoutB = multiprocessing.Queue()

    class B():
        # Queue as global variable
        def __init__(self):
            self.qout = qoutB

        def worker(self, x):
            self.qout.put(x*x)

        def process(self):
            values = range(10)
            with multiprocessing.Pool() as pool:
                res = pool.map_async(self.worker, values)
                classname = type(self).__name__
                print(classname, '- while loop starting')
                while not self.qout.empty() or not res.ready():
                    val = self.qout.get()
                    print(val)
                print(classname, '- while loop ended')


elif TEST_CLASS_NAME == 'C':

    class C():
        # Queue as Class variable
        qout = multiprocessing.Queue()

        def __init__(self):
            pass

        def worker(self, x):
            self.qout.put(x*x)

        def process(self):
            values = range(10)
            with multiprocessing.Pool() as pool:
                res = pool.map_async(self.worker, values)
                classname = type(self).__name__
                print(classname, '- while loop starting')
                while not self.qout.empty() or not res.ready():
                    val = self.qout.get()
                    print(val)
                print(classname, '- while loop ended')


if __name__ == '__main__':

    print('testing class', TEST_CLASS_NAME)
    Class = globals()[TEST_CLASS_NAME]
    test = Class()
    test.process()

    print('done')

答案 1 :(得分:0)

SO算法给了我有趣的提示,这是我以前找不到的。

基于this answer,队列不能作为参数传递给正在打开新进程的函数,因为队列不能被腌制。这就是一般self.function()所做的:它等效于function(self)。对于类A,尝试将队列传递给工作程序;与BC中的情况不同,而该过程或多或少地独立于该过程

this question and answers得出相同的结论。不用说,manager.Queue在这里也不起作用。

MCVE测试失败

这可能是由于multiprocessingsee docs)的默认默认启动方法造成的。

答案 2 :(得分:0)

同样,这不是您的问题的答案。但是,我要发布它是因为它使整个问题变得毫无意义—因为您实际上不需要显式创建并使用multiprocessing.Queue来执行类似的操作。

请改为考虑使用concurrent.futures.ProcessPoolExecutor完成任务。

例如:

import concurrent.futures

class A_Prime():
    def __init__(self):
        pass

    def worker(self, x):
        return x*x

    def process(self):
        with concurrent.futures.ProcessPoolExecutor() as executor:
            classname = type(self).__name__
            print(classname, '- calling executor.map')
            res = [value for value in executor.map(self.worker, range(10))]
            print(classname, '- executor.map finished')
            print('  result:', res)


if __name__ == '__main__':
    test = A_Prime()
    test.process()
    print('done')

输出:

A_Prime - calling executor.map
A_Prime - executor.map finished
  result: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
done