5

下面是一个完整简单的工作示例Optimzing multiprocessing.Pool昂贵的初始化

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() 

如何修改它,以便美孚仅由每个工人,不是每一个任务初始化一次?基本上我想在init称为4倍,而不是10。我使用Python 3.5

+0

如果该类初始化一次,然后复制到每个工作人员,会好吗? –

+0

@BrendanAbel我认为是。那意味着对象必须是可以腌制的?该对象在初始化后永远不会发生变化,所以我不知道为什么复制会很糟糕。 – user2133814

+0

多处理与多线程不同。他们有很大不同的特点。 – jpmc26

回答

6

预期的方式来处理这样的事情是通过可选的initializerinitargs参数到Pool()构造函数。它们的存在正是为了让您在创建工作进程时精确地执行一次任务。因此,例如添加:

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

,改变Pool创建于:

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

如果你需要传递参数给你的每个进程初始化函数,那么你也想加入适量initargs=...论据。

注:当然,你也应该从f()删除

foo = Foo() 

线,让你的函数使用init()创建全球foo

+0

您能否在此解释全局关键字。我在文档中看到了初始化器,但没有想到/了解“全局”,所以我没有看到如何使其工作。谢谢 – user2133814

+0

刚才看到我的编辑:您还需要使用由初始化函数创建的'foo'。初始化函数运行一次并结束,因此它所做的任何更改都必须在全局范围内可见,以便稍后使用其他函数(例如'map()'调用)可以受益。 –

+1

。没有任何内容在进程间共享。自从第1天开始,'global'就已经开始使用Python了,多年前'multiprocessing'甚至是一个模块的想法。 'global'与进程(或线程)无关。在上下文中,它只是告诉'init()'在模块的全局范围内而不是在(默认的)'init'的本地范围内绑定'foo'。在多处理中,每个进程都有自己独特的模块全局名称空间。 –

2

最为明显,延迟加载

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

混淆为什么你有一个从未被引用的全局'_foo'? – Bakuriu