使用multiprocessing.Pool时如何理解multiprocessing.Queue?

时间:2018-12-24 08:18:52

标签: python multiprocessing

为什么不能将process中的Pool放入Queue中?
在这里,我的代码在使用Pool时有效,并且可以获得Test实例属性。

from multiprocessing import Pool
from multiprocessing import Queue


class Test(object):
    def __init__(self, num):
        self.num = num


if __name__ == '__main__':
    p = Pool()
    procs = []
    for i in range(5):
        proc = p.apply_async(Test, args=(i,))
        procs.append(proc)
    p.close()
    for each in procs:
        test = each.get(10)
        print(test.num)
    p.join()

当我尝试使用Queue而不是python list来存储进程时,这将不起作用。

我的代码:

from multiprocessing import Pool
from multiprocessing import Queue


class Test(object):
    def __init__(self, num):
        self.num = num


if __name__ == '__main__':
    p = Pool()
    q = Queue()
    for i in range(5):
        proc = p.apply_async(Test, args=(i,))
        q.put(proc)
    p.close()
    while not q.empty():
        q.get()
    p.join()

错误消息:

Traceback (most recent call last):
  File "C:\Users\laich\AppData\Local\Programs\Python\Python36- 
32\lib\multiprocessing\queues.py", line 234, in _feed
    obj = _ForkingPickler.dumps(obj)
  File "C:\Users\laich\AppData\Local\Programs\Python\Python36- 
32\lib\multiprocessing\reduction.py", line 51, in dumps
    cls(buf, protocol).dump(obj)
TypeError: can't pickle _thread.lock objects

我去看看多处理文档:

  

class multiprocessing.Queue([maxsize])   返回使用管道和一些锁/信号量实现的进程共享队列。当进程首先将项目放入队列时,将启动一个供料器线程,该线程将对象从缓冲区转移到管道中。

     

标准库的队列模块中常见的queue.Emptyqueue.Full异常引发了超时。

     

queue.Queuetask_done()之外,Queue实现了join()的所有方法。

这里说“放一个东西”,这个东西不能是任何东西(python对象)?以我为例,我尝试将process中的Pool()放入Queue中。

2 个答案:

答案 0 :(得分:0)

基于Queue的代码至少存在两个问题。 Pool.apply_async方法返回一个AsyncResult对象,而不是进程。您可以对此对象调用get,以获取相应过程的结果。考虑到这种差异,让我们看一下您的代码:

proc = p.apply_async(Test, args=(i,)) # Returns an AsyncResult object
q.put(proc) # won't work

根据您的情况,第二行将始终失败。您放入队列中的任何内容都必须是可挑剔的,因为multiprocess.Queue使用序列化。这没有很好的文档说明,Python的问题跟踪器中有一个open issue用于更新文档。问题是AsyncResult不可腌制。您可以尝试一下:

import pickle
import multiprocessing as mp

with mp.Pool() as p:
    result = p.apply_async(lambda x: x, (1,))

pickle.dumps(result) # Error

AsyncResult内部包含一些锁定对象,并且它们无法序列化。让我们转到下一个问题:

while not q.empty():
    q.get()

如果我没记错的话,在上面的代码中,您想调用AsyncResult.get而不是Queue.get。在这种情况下,您必须首先从队列中获取对象,然后在对象上调用相应的方法。但是,由于AsyncResult不可序列化,因此代码中不是这种情况。

答案 1 :(得分:0)

就像@Mehdi Sadeghi explained一样,AsyncResult个对象不能被腌制,multiprocessing.Queue被要求。但是,这里不需要一个队列,因为队列没有在进程之间共享。这意味着您只能使用常规的Queue

from multiprocessing import Pool
#from multiprocessing import Queue
from queue import Queue


class Test(object):
    def __init__(self, num):
        self.num = num
        print('Test({!r}) created'.format(num))


if __name__ == '__main__':
    p = Pool()
    q = Queue()
    for i in range(5):
        proc = p.apply_async(Test, args=(i,))
        q.put(proc)
    p.close()
    while not q.empty():
        q.get()
    p.join()

    print('done')

输出:

Test(0)
Test(1)
Test(2)
Test(3)
Test(4)
done