2016-07-05 12 views
1

Ich habe versucht, meinen Code zu verbessern (mit Numba und Multiprocessing), aber ich kann es nicht ganz bekommen, weil meine Funktion viele Argumente hat.Implementierung von Pool auf einer for-Schleife mit vielen Eingaben

ich es bereits mit anderen Funktionen vereinfacht haben (siehe unten) ...

Da jeder Agent (eine Klasseninstanz) unabhängig voneinander für diese Aktionen, würde Ich mag die for mit Pool ersetzen.

So würde ich eine große Funktion erhalten pooling(), die ich nennen würde und übergeben Sie die Liste der Agenten

from multiprocessing import Pool 

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

Aber, wo ich alle Argumente hinzufügen, dass die Pooling-Funktion benötigt?

wie es ist:

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) 

Es ist die meiste Zeit ist in meinem Programm raubend Funktion. Und @jit hilft nicht viel.

Dank einem Haufen

+1

Hinweis: Die globale Variable oder der Parameter '' my_graveyard'' fehlt. –

+0

In der Tat, danke. –

Antwort

1

Ja, es gibt eine Menge von Parametern! Erwägen Sie die Verwendung einer Klasse.

Nun, da Pool.map nur ein iterables Argument unterstützt, müssen Sie alles an einem Ort gruppieren. Ich empfehle Ihnen, das "Facade" -Muster zu verwenden: eine Zwischenklasse, die verwendet wird, um alle erforderlichen Parameter zu speichern und eine einzige Methode (ich nenne sie check) ohne Parameter zu verwenden (es ist eine Methode).

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) 

Bemerkung: mein Refactoring ist wirklich hässlich, aber ich wollte für Klarheit Variablennamen unverändert halten. so etwas wie das

Dann können Sie Ihre Schleife:

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) 

Sie sagten, dass jeder Agent voneinander unabhängig, aber nach der Schleife zu analysieren, ich sehe, dass Sie die komplette Liste der Agenten müssen (die my_agents Parameter). Es ist offensichtlich mit der Facade Klasse. Daher darf sich Ihre Agentenliste nicht ändern und der interne Status jedes Agenten muss während des Schleifens eingefroren sein.

+0

Ausgezeichnet, danke. Aber du hast recht, die Liste 'my_agents' ändert sich. Deshalb habe ich eine neue 'Liste (Agenten) 'erstellt, durch die ich iteriere. Wird das in diesem Fall funktionieren? –

+0

Mindestens gelten '' map'' auf der Kopie der Agenten: '' list (agents) ''. Warum ändert sich die Liste? –

+0

tat ich. Ich habe auch diesen Fehler '_pickle.PicklingError: Kann nicht : Attribut-Lookup-Check auf Demographie fehlgeschlagen' Die Liste ändert sich, weil ich einen Agenten entfernen muss, wenn er/sie stirbt. Und in Ihrem Beispiel habe ich den Agenten erst, nachdem ich die 'for-Schleife 'initiiert habe. –