使用多处理从另一个类使用函数更新类对象

时间:2017-04-25 08:59:06

标签: python performance multiprocessing

我有一个类Individual,它由类change_val的实例组成。可以使用函数import numpy as np import multiprocessing as mp class Population(object): def __init__(self, pool_proc): self.individuals = [] self.pool_proc = pool_proc def add_individual(self, individual): self.individuals.append(individual) def change_individuals_loop(self): # in a loop, it works fine for indi in self.individuals: indi.change_val() def change_individuals_multi(self): # this does -of course - not work as change_val is not known. How would it be done correctly? self.pool_proc.apply_async(change_val, self.individuals) def print_pop(self): for indi in self.individuals: print "value: {}, exponent: {}".format(indi.val, indi.exponent) class Individual(object): def __init__(self, some_val, exponent): self.val = some_val self.exponent = exponent def change_val(self): self.val = self.val ** self.exponent if __name__ == '__main__': # just for reproducibility purposes np.random.seed(1) my_pool = mp.Pool(processes=5) my_pop = Population(my_pool) for indi in range(1, 6): my_pop.add_individual(Individual(indi, np.random.choice(5))) print "initially:" my_pop.print_pop() my_pop.change_individuals_loop() print "\nfirst iteration:" my_pop.print_pop() 来更改个体的属性;在我的实际代码中,这种变化可能需要很长时间,处理时间可能会因人而异。一个人的变化独立于其他个体,因此我想使用多处理来加速更新所有个体的过程(与仅使用简单的for循环相比)。

这是我的玩具系统代码的骨架:

change_individuals_multi

我的问题是如何重写函数change_individuals_loop,以便它为我提供与self.pool_proc.apply_async(change_val, self.individuals) 相同的输出。

问题在于行

change_val

当然 - 不起作用,因为函数apply_async未知。我如何修改此行或代码结构以使其工作?如果有更适合这些目的的事情而不是 var oAjax = new XMLHttpRequest; oAjax.open( 'get', '/path/to/my/app.js' ); oAjax.setRequestHeader( 'Pragma', 'no-cache' ); oAjax.send(); oAjax.onreadystatechange = function() { if( oAjax.readyState === 4 ) { self.location.reload(); } } ,那么这方面的建议非常受欢迎。

1 个答案:

答案 0 :(得分:1)

将它变成一个函数:

self.pool_proc.apply_async(lambda individual: individual.change_val(), self.individuals)

要获取值,您需要返回一些内容,然后处理返回值。有很多方法可以做到这一点,例如:

from multiprocessing import Pool

def workerfn((ndx, individual)):
    individual.change_val()
    return ndx, individual.val

...
pool = Pool(...)
for ndx, val in pool.imap_unordered(workerfn, enumerate(self.individuals)):
    self.individuals[ndx].val = val

更新:为什么10万人的多重治疗速度较慢?

大多数尝试过多线程/处理的人都会遇到这种情况。原因很简单:开销。在单线程版本中,您执行函数调用+指数+赋值,而在多线程版本中,您可以执行在单线程版本中执行的所有操作+启动流程池+序列化100K个人+反序列化100K个人+进程间通信(个人)+序列化100K结果+反序列化相同+进程间通信(结果)+将结果分配给对象...我不会感到惊讶它的速度较慢;-)

为了使多个进程在常规多核设置上更快地运行(我不是在谈论100个核心),您需要大量的工作/数据,分成更大的块,然后分配给每个进程。例如。除以100 000 /核心数量并发送个人列表,而不是逐个发送。

当您将对象发送到另一个进程时,Python需要序列化和反序列化它们,因为另一个进程运行一个完全独立的Python解释器。与发送诸如元组/列表/等基本类型相比,这需要花费大量时间。尝试发送计算参数而不是单个对象。

最后,要完成的工作量需要花费更长的时间来进行进程间调用+返回。