首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python multiprocessing.Queue vs multiprocessing.manager().Queue()

Python multiprocessing.Queue vs multiprocessing.manager().Queue()
EN

Stack Overflow用户
提问于 2017-04-17 00:10:50
回答 2查看 25.5K关注 0票数 57

我有一个这样的简单任务:

代码语言:javascript
复制
def worker(queue):
    while True:
        try:
            _ = queue.get_nowait()
        except Queue.Empty:
            break

if __name__ == '__main__':
    manager = multiprocessing.Manager()
    # queue = multiprocessing.Queue()
    queue = manager.Queue()

    for i in range(5):
        queue.put(i)

    processes = []

    for i in range(2):
        proc = multiprocessing.Process(target=worker, args=(queue,))
        processes.append(proc)
        proc.start()

    for proc in processes:
        proc.join()

似乎multiprocessing.Queue可以完成我需要的所有工作,但另一方面,我看到了许多.Queue()的示例,无法理解我真正需要的是什么。看起来管理器().Queue()使用了某种代理对象,但我不理解这些用途,因为multiprocessing.Queue()在没有任何代理对象的情况下也做同样的工作。

所以,我的问题是:

1) multiprocessing.Queue和multiprocessing.manager().Queue()返回的object到底有什么区别?

2)我需要使用什么?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-07-21 19:40:03

虽然我对这个主题的理解有限,但从我所做的事情可以看出,multiprocessing.Queue()和multiprocessing.Manager().Queue()之间有一个主要的区别:

  • multiprocessing.Queue()是一个对象,而multiprocessing.Manager().Queue()是一个指向由multiprocessing.Manager()池管理的共享队列的地址(代理)您不能将普通的multiprocessing.Queue()对象传递到池方法,因为它不能被python doc告知我们在使用multiprocessing.Queue()时要特别注意,因为它可能会对

产生不必要的影响

备注将对象放入队列时,该对象将被pickled,然后后台线程将pickled的数据刷新到底层管道中。这有一些令人惊讶的结果,但不应该造成任何实际困难-如果它们真的困扰您,那么您可以使用由管理器创建的队列。将对象放入空队列后,在队列的empty()方法返回False之前,可能会有无限小的延迟,并且get_nowait()可以在不引发Queue.Empty的情况下返回。如果多个进程正在将对象入队,则可能会在另一端无序接收这些对象。但是,由同一进程入队的对象将始终按照彼此的预期顺序排列。

警告如上所述,如果子进程已将项放入队列(并且未使用JoinableQueue.cancel_join_thread),则该进程将不会终止,直到所有缓冲的项都被刷新到管道中。这意味着,如果您尝试加入该进程,则可能会出现死锁,除非您确定已放入队列的所有项都已被使用。类似地,如果子进程是非守护进程,那么当父进程试图加入所有非守护进程的子进程时,它可能会在退出时挂起。请注意,使用管理器创建的队列不存在此问题。

通过将队列设置为全局变量并在初始化时为所有进程设置它,可以在池中使用multiprocessing.Queue():

代码语言:javascript
复制
queue = multiprocessing.Queue()
def initialize_shared(q):
    global queue
    queue=q

pool= Pool(nb_process,initializer=initialize_shared, initargs(queue,))

将创建具有正确共享队列的池进程,但我们可以争辩说,multiprocessing.Queue()对象不是为此用途而创建的。

另一方面,通过将manager.Queue()作为函数的普通参数传递,可以在池子进程之间共享它。

在我看来,使用multiprocessing.Manager().Queue()在任何情况下都很好,而且麻烦也少一些。使用管理器可能会有一些缺点,但我不知道这一点。

票数 45
EN

Stack Overflow用户

发布于 2020-01-09 19:22:46

我最近遇到了一个关于Manager().Queue()的问题,当multiprocessing.Manager()返回的SyncManager对象似乎死了,它管理的队列永远阻塞(即使使用*_nowait()也是如此)。

我不确定原因,或者如果SyncManager真的死了,唯一的线索是我从一个类实例调用multiprocessing.Manager(),它有__del__(),它记录了调用它的进程,我可以看到这是从SyncManager进程调用的__del__()

这意味着我的对象在SyncManager进程中有一个副本,并且它被垃圾回收了。这可能意味着只删除了我的对象,SyncManager没有问题,但我确实看到相应的队列变得没有响应,这与SyncManager进程中的__del__()调用相关。

我不知道我的对象是如何在SyncManager进程中结束的。在我发现这个问题之前,我通常会抽出50-200名经理--有些人的生命周期重叠,另一些人则不然。对于解释器退出时存在的对象,不会调用__del__(),而且我通常不会在__del__()中看到SyncManager对象因此日志而消亡,只是偶尔会这样。可能当出现问题时,SyncManager对象首先处理它的对象,然后解释器才会退出,这就是为什么我偶尔会看到__del__()调用的原因。

我确实看到我的队列变得没有响应,即使在我没有看到从SyncManager调用__del__()的情况下也是如此。

我还看到SyncManager“死了”,没有引起更多的问题。

我所说的“无响应”是指:

代码语言:javascript
复制
queue.get(timeout=1)
queue.put(timeout=1)

一去不复返。

代码语言:javascript
复制
queue.get_nowait(timeout=1)
queue.put_nowait(timeout=1)

一去不复返。

这变得有点复杂,比我最初想要的要复杂一些,但我让细节进来,以防它对某人有帮助。

我使用Manager().Queue()很长一段时间了,没有任何问题。我怀疑要么是实例化了许多管理器对象导致了问题,要么是实例化了许多管理器导致了一个表面上一直存在的问题。

我使用Python 3.6.5

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43439194

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档