在for循环中实现具有大量输入的池

时间:2016-07-05 20:35:04

标签: python performance multiprocessing pool

我一直在努力改进我的代码(使用numba和多处理),但我无法理解它,因为我的函数有很多参数。

我已经用其他功能简化了它(见下文)......

由于每个代理(类实例)对于这些操作彼此独立,我想将for替换为Pool

所以我会得到一个大函数pooling(),我会调用它并传递代理列表

from multiprocessing import Pool

p = Pool(4)
p.map(pooling, list(agents))

但是,我在哪里添加池函数需要的所有参数?

原样:

def check_demographics(month, my_agents, families, firms, year, mortality_men, mortality_women, fertility, state_id):

    dummy = list(my_agents)
    d = str(state_id.iloc[0])

# Place where I would like to replace the LOOP. All below would be a function 

    for agent in dummy:

        if agent.get_region_id()[:2] == d:

            # Brithday
            if month % 12 == agent.month - 1:
                agent.update_age()

            # Mortality probability 
            if agent.get_gender() == 'Male':
                prob = mortality_men[mortality_men['age'] == agent.get_age()][year].iloc[0]

            # When gender is Female
            else:
                # Extract specific agent data to calculate mortality 'Female'
                prob = mortality_women[mortality_women['age'] == agent.get_age()][year].iloc[0]

            # Give birth decision 
                age = agent.get_age()
                if 14 < age < 50:
                    pregnant(agent, fertility, year, families, my_agents)

            # Mortality procedures 
            if fixed_seed.random() < prob:
                mortal(my_agents, my_graveyard, families, agent, firms)

这是我程序中最耗时的功能。 @jit并没有多大帮助。

非常感谢

1 个答案:

答案 0 :(得分:1)

是的,有很多参数!考虑使用一个类。

好吧,由于Pool.map只支持一个可迭代参数,因此您需要将所有内容分组到一个位置。我建议你使用&#34; Facade&#34; pattern:一个中间类,用于存储所有必需参数,并且只有一个方法(我称之为check)没有参数(它是一个方法)。

class Facade(object):
    def __init__(self, agent, d, families, fertility, firms, month, mortality_men, mortality_women, my_agents,
                 my_graveyard, year):
        self.agent = agent
        self.d = d
        self.families = families
        self.fertility = fertility
        self.firms = firms
        self.month = month
        self.mortality_men = mortality_men
        self.mortality_women = mortality_women
        self.my_agents = my_agents
        self.my_graveyard = my_graveyard
        self.year = year

    def check(self):
        (agent, d, families, fertility, firms,
         month, mortality_men, mortality_women,
         my_agents, my_graveyard, year) = (
            self.agent, self.d, self.families, self.fertility, self.firms,
            self.month, self.mortality_men, self.mortality_women,
            self.my_agents, self.my_graveyard, self.year)
        if agent.get_region_id()[:2] == d:

            # Brithday
            if month % 12 == agent.month - 1:
                agent.update_age()

            # Mortality probability
            if agent.get_gender() == 'Male':
                prob = mortality_men[mortality_men['age'] == agent.get_age()][year].iloc[0]

            # When gender is Female
            else:
                # Extract specific agent data to calculate mortality 'Female'
                prob = mortality_women[mortality_women['age'] == agent.get_age()][year].iloc[0]

                # Give birth decision
                age = agent.get_age()
                if 14 < age < 50:
                    pregnant(agent, fertility, year, families, my_agents)

            # Mortality procedures
            if fixed_seed.random() < prob:
                mortal(my_agents, my_graveyard, families, agent, firms)

备注:我的重构非常难看,但为了清晰起见,我想保持变量名称不变。

然后你的循环可以是这样的:

def check_demographics(month, my_agents, families, firms,
                       year, mortality_men, mortality_women,
                       fertility, state_id, my_graveyard):
    d = str(state_id.iloc[0])
    pool = Pool(4)
    facades = [Facade(agent, d, families, fertility, firms,
                      month, mortality_men, mortality_women,
                      my_agents, my_graveyard, year)
               for agent in my_agents]
    pool.map(Facade.check, facades)

你说每个代理都是相互独立的,但是在分析了循环后,我发现你需要完整的代理列表(my_agents参数)。对于Facade类来说,这很明显。因此,您的代理列表不得更改,并且在循环期间必须冻结每个代理的内部状态。