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

Python 使用函数从另一个使用多处理的类更新类对象,python,performance,multiprocessing,Python,Performance,Multiprocessing,我有一个类Population,它由一个类个体的实例组成。可以使用函数change\u val更改个人的属性;在我的实际代码中,这种更改可能需要很长的时间,并且处理时间可能会因个人而异。一个个体的变化是独立于其他个体的,因此我想使用多处理来加速更新群体中所有个体的过程(与仅使用简单的for循环相比) 这是我的玩具系统代码的框架: import numpy as np import multiprocessing as mp class Population(object): def

我有一个类
Population
,它由一个类
个体的实例组成。可以使用函数
change\u val
更改个人的属性;在我的实际代码中,这种更改可能需要很长的时间,并且处理时间可能会因个人而异。一个个体的变化是独立于其他个体的,因此我想使用多处理来加速更新群体中所有个体的过程(与仅使用简单的for循环相比)

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

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()
我的问题是如何重写函数
change\u personals\u multi
,以便它提供与
change\u personals\u loop
相同的输出

问题是这条线

self.pool_proc.apply_async(change_val, self.individuals)

由于函数
change\u val
未知,因此不工作。我必须如何修改这一行或代码结构才能使其工作?如果有比“应用异步”更适合于这些目的的东西,那么这方面的建议是非常受欢迎的。

将其变成一个函数:

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个核)上更快地工作,您需要大量的工作/数据,并将其划分为更大的块,分发给每个进程。例如,将10万个/芯数分开,并发送个人列表,而不是逐个发送

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


最后,要完成的工作量需要比进程间调用+返回所需的时间更长。

谢谢。不幸的是,当我运行
my\u pop.change\u personals\u multi()
时,这不会更新我的个人。你能试着运行它吗,也许我错过了什么。。。!?它会更新,但只更新发送到子流程的单个文件的副本(这不是共享内存,而是复制的值)。如果您想要返回结果,您需要为其创建一种机制,如map\u async+a返回值+a for-loop这给了我
TypeError:workerfn()正好接受2个参数(给定1个)
。另外,你还需要你在回答中发布的第一行吗?我有一个使用imap_无序的代码示例,它可能是最接近映射异步的意思。初始化池一次效果很好,但需要一段时间,因此有时在需要时初始化它会更好。