我有一个令人尴尬的可并行化问题,包括一堆彼此独立解决的任务。解决每个任务非常冗长,因此这是多处理的主要候选者。
问题是解决我的任务需要创建一个非常耗时的特定对象,但可以重用于所有任务(想想需要启动的外部二进制程序),所以在串行版本中我做这样的事情:
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
当我尝试使用多处理并行化此程序时,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()
但是创建my_object
的多个实例所增加的成本使得此代码仅略微快于序列化代码。
如果我可以在每个进程中创建一个单独的my_object
实例,然后将其重用于该进程中运行的所有任务,那么我的时间将会显着改善。有关如何做到这一点的任何指示?
答案 0 :(得分:7)
我找到了一种简单的方法来解决我自己的问题而不引入除标准库之外的任何工具,我想我会把它写在这里以防其他人有类似的问题。
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()
由于每个进程都有一个单独的全局命名空间,因此实例化的对象不会发生冲突,并且每个进程只创建一次。
可能不是最优雅的解决方案,但它足够简单并且给我一个接近线性的加速。
答案 1 :(得分:1)
你可以让celery project为你处理这一切,在许多其他功能中,它还可以运行一些任务initialization,后者可以被所有任务使用
答案 2 :(得分:1)
使用multiprocessing
时,您被限制为可选对象。你绝对确定你的物品是不可拾取的吗?
你试过dill
吗?如果你导入它,任何时候调用pickle它将使用莳萝绑定。当我尝试在sympy
方程上使用多处理时,它对我有用。