【问题标题】:Can I safely use global Queues when using multiprocessing in python?在 python 中使用多处理时,我可以安全地使用全局队列吗?
【发布时间】:2015-10-01 13:22:13
【问题描述】:

我有一个庞大的代码库要并行化。通过使用单个全局队列,我可以避免重写数百个函数的方法签名。我知道这很乱;请不要告诉我,如果我使用全局变量,在这种情况下我做错了什么,这确实是最简单的选择。下面的代码有效,但我不明白为什么。我声明了一个全局 multiprocessing.Queue() 但没有声明它应该在进程之间共享(通过将它作为参数传递给工作人员)。 python 会自动将此队列放在共享内存中吗?在更大范围内这样做是否安全?

注意:您可以看出队列是在进程之间共享的:工作进程开始在空队列上工作,并且在主队列将一些工作推入队列之前空闲一秒钟。

import multiprocessing
import time

outqueue = None


class WorkerProcess(multiprocessing.Process):
    def __init__(self):
        multiprocessing.Process.__init__(self)
        self.exit = multiprocessing.Event()

    def doWork(self):
        global outqueue
        ob = outqueue.get()
        ob = ob + "!"
        print ob
        time.sleep(1) #simulate more hard work
        outqueue.put(ob)

    def run(self):
        while not self.exit.is_set():
            self.doWork()

    def shutdown(self):
        self.exit.set()

if __name__ == '__main__':
    global outqueue
    outqueue = multiprocessing.Queue()

    procs = []
    for x in range(10):
        procs.append(WorkerProcess())
        procs[x].start()

    time.sleep(1)
    for x in range(20):
        outqueue.put(str(x))

    time.sleep(10)
    for p in procs:
        p.shutdown()

    for p in procs:
        p.join()

    try:
        while True:
            x = outqueue.get(False)
            print x
    except:
        print "done"

【问题讨论】:

  • 我强烈建议阅读this question 的答案,而不是下面接受的答案,我认为这是完全错误的。

标签: python multithreading multiprocessing shared-memory python-multiprocessing


【解决方案1】:

假设您使用的是 Linux,答案是操作系统创建新进程的方式。

当一个进程在 Linux 中生成一个新进程时,它实际上会派生出父进程。结果是一个具有父进程所有属性的子进程。基本上是一个克隆。

在您的示例中,您正在实例化队列,然后创建新进程。因此,子进程将拥有相同队列的副本并且能够使用它。

要查看损坏的内容,请先尝试创建进程,然后再创建 Queue 对象。您会看到子级的全局变量仍设置为 None,而父级将有一个队列。

在 Linux 上共享队列作为全局变量是安全的,但不推荐。在 Windows 上,由于进程创建方式不同,无法通过全局变量共享队列。

programming guidelines中所述

将资源显式传递给子进程

在使用 fork start 方法的 Unix 上,子进程可以使用在使用全局资源的父进程中创建的共享资源。但是,最好将对象作为参数传递给子进程的构造函数。

除了使代码(可能)与 Windows 和其他启动方法兼容之外,这还确保只要子进程仍然存在,该对象就不会在父进程中被垃圾收集。如果在父进程中对对象进行垃圾回收时释放了某些资源,这可能很重要。

有关 Linux 分叉的更多信息,您可以阅读其man page

【讨论】:

  • 我很抱歉投反对票,但我认为这是不正确的。根据个人经验,这可能会导致进程无法将get 消息put 发送到另一个进程的队列中。我建议看this question的答案。
  • “将队列作为全局变量共享是安全的,但不推荐。”:它似乎在 Windows 上不起作用。请参阅我的问题:stackoverflow.com/questions/42734348/…
  • @max:正如答案中所说,我专注于Linux。我根据您的评论更新了答案。
  • @AmiTavory:不太明白你评论的意思。链接的问题没有提供足够的代码来重现该问题。 multiprocessing.Queue 对象是进程安全的。然而,由于大多数同步原语很容易被误用和误解。这不是工具,是你使用它的方式;)
猜你喜欢
  • 1970-01-01
  • 2011-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-10
  • 2017-04-27
  • 2011-04-19
  • 2022-01-10
  • 1970-01-01
相关资源
最近更新 更多