【问题标题】:Optimizing multiprocessing.Pool with expensive initialization使用昂贵的初始化优化 multiprocessing.Pool
【发布时间】:2016-12-12 06:12:00
【问题描述】:

这是一个完整的简单工作示例

import multiprocessing as mp
import time
import random


class Foo:
    def __init__(self):
        # some expensive set up function in the real code
        self.x = 2
        print('initializing')

    def run(self, y):
        time.sleep(random.random() / 10.)
        return self.x + y


def f(y):
    foo = Foo()
    return foo.run(y)


def main():
    pool = mp.Pool(4)
    for result in pool.map(f, range(10)):
        print(result)
    pool.close()
    pool.join()


if __name__ == '__main__':
    main()

如何修改它,以便 Foo 仅由每个工作人员初始化一次,而不是每个任务?基本上我希望 init 被调用 4 次,而不是 10 次。我使用的是 python 3.5

【问题讨论】:

  • 如果类只初始化一次,然后复制到每个worker,会不会很好?
  • @BrendanAbel 我想是的。这意味着对象必须是可腌制的?该对象在初始化后永远不会发生变异,所以我不知道为什么复制会不好
  • 多处理与多线程相同。它们具有截然不同的特征。
  • 抱歉问题标题中的混淆

标签: python python-3.5 python-multiprocessing pool object-initializers


【解决方案1】:

处理此类事情的预期方法是通过Pool() 构造函数的可选initializerinitargs 参数。它们的存在正是为了给你一种在创建工作进程时只做一次事情的方法。因此,例如,添加:

def init():
    global foo
    foo = Foo()

并将Pool 创建更改为:

pool = mp.Pool(4, initializer=init)

如果您需要将参数传递给每个进程的初始化函数,那么您还需要添加一个适当的 initargs=... 参数。

注意:当然你也应该删除

foo = Foo()

来自f() 的行,以便您的函数使用init() 创建的全局foo

【讨论】:

  • 你能解释一下这个上下文中的全局关键字吗?我在文档中看到了初始化程序,但没有想到/不知道“全局”,所以我不知道如何使它工作。谢谢
  • 看我刚才的编辑:你还需要使用初始化函数创建的foo。初始化函数运行一次并结束,因此它所做的任何更改都必须在全局范围内可见,以便以后的其他函数(例如由map() 调用)可以受益。
  • 没有。没有什么是跨进程共享的。 global 从第一天起就在 Python 中,很多年之前 multiprocessing 甚至是一个模块的想法。 global 与进程(或线程)无关。在上下文中,它只是告诉init() 在模块的全局范围内绑定foo,而不是在(默认)init 的本地范围内。在多处理中,每个进程都有自己独特的模块全局命名空间。
【解决方案2】:

最明显的延迟加载

_foo = None
def f(y):
    global _foo
    if not _foo:
       _foo = Foo()
    return _foo.run(y)

【讨论】:

  • 为什么你有一个从未被引用的全局_foo
猜你喜欢
  • 2012-09-20
  • 2012-02-02
  • 2020-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
  • 2022-01-12
相关资源
最近更新 更多