在python进程中创建和重用对象

Jav*_*ier 3 python pool multiprocessing

我有一个令人尴尬的可并行化的问题,包括一堆彼此独立解决的任务.解决每个任务是相当漫长的,因此这是多处理的主要候选者.

问题是解决我的任务需要创建一个非常耗时的特定对象,但可以重用于所有任务(想想需要启动的外部二进制程序),所以在串行版本中我做了一些事情像这样:

def costly_function(task, my_object):
    solution = solve_task_using_my_object
    return solution

def solve_problem():
    my_object = create_costly_object()
    tasks = get_list_of_tasks()
    all_solutions = [costly_function(task, my_object) for task in tasks]
    return all_solutions
Run Code Online (Sandbox Code Playgroud)

当我尝试使用多处理并行化该程序时,my_object由于多种原因(它不能被腌制,并且它不应该同时运行多个任务)而不能作为参数传递,所以我不得不求助于创建一个每个任务的单独对象实例:

def costly_function(task):
    my_object = create_costly_object()
    solution = solve_task_using_my_object
    return solution

def psolve_problem():
    pool = multiprocessing.Pool()
    tasks = get_list_of_tasks()
    all_solutions = pool.map_async(costly_function, tasks)
    return all_solutions.get()
Run Code Online (Sandbox Code Playgroud)

但是创建多个实例的额外成本my_object使得此代码仅略微快于序列化代码.

如果我可以my_object在每个进程中创建一个单独的实例,然后将其重用于在该进程中运行的所有任务,那么我的时间将显着提高.有关如何做到这一点的任何指示?

Jav*_*ier 9

我发现了一种简单的方法来解决我自己的问题而不引入除标准库之外的任何工具,我想我会把它写在这里以防其他人有类似的问题.

multiprocessing.Pool接受initializer在启动每个进程时运行的函数(带参数).此函数的返回值不会存储在任何位置,但可以利用该函数来设置全局变量:

def init_process():
    global my_object
    my_object = create_costly_object()

def costly_function(task):
    global my_object
    solution = solve_task_using_my_object
    return solution

def psolve_problem():
    pool = multiprocessing.Pool(initializer=init_process)
    tasks = get_list_of_tasks()
    all_solutions = pool.map_async(costly_function, tasks)
    return all_solutions.get()
Run Code Online (Sandbox Code Playgroud)

由于每个进程都有一个单独的全局命名空间,因此实例化的对象不会发生冲突,并且每个进程只创建一次.

可能不是最优雅的解决方案,但它足够简单并且给我一个接近线性的加速.