2012-04-14 16 views
7

Dies (enorm vereinfachtes Beispiel) funktioniert gut (Python 2.6.6, Debian Squeeze):Alternative Nutzungsmuster für Python-Multiprozessing, die Vermehrung des globalen Zustands vermeiden?

from multiprocessing import Pool 
import numpy as np 

src=None 

def process(row): 
    return np.sum(src[row]) 

def main(): 
    global src 
    src=np.ones((100,100)) 

    pool=Pool(processes=16) 
    rows=pool.map(process,range(100)) 
    print rows 

if __name__ == "__main__": 
    main() 

jedoch nach Jahren der globaler Zustand schlecht gelehrt !!!, alle meine Instinkte sagen mir etwas näher an wirklich, ich würde wirklich lieber schreiben:

from multiprocessing import Pool 
import numpy as np 

def main(): 
    src=np.ones((100,100)) 

    def process(row): 
     return np.sum(src[row]) 

    pool=Pool(processes=16) 
    rows=pool.map(process,range(100)) 
    print rows 

if __name__ == "__main__": 
    main() 

aber das ist natürlich nicht funktioniert (auflegt nicht in der Lage, etwas beizen).

Das Beispiel hier ist trivial, aber wenn Sie mehrere "Prozess" -Funktionen hinzufügen, und jede davon ist abhängig von mehreren zusätzlichen Eingaben ... Nun, es erinnert ein bisschen an etwas in BASIC vor 30 Jahren geschrieben . Der Versuch, Klassen zu verwenden, um zumindest den Zustand mit den entsprechenden Funktionen zu aggregieren, scheint eine naheliegende Lösung zu sein, aber in der Praxis ist es doesn't seem to be that easy.

Gibt es einige empfohlene Muster oder Stile für die Verwendung von multiprocessing.pool, die die Verbreitung des globalen Zustands zur Unterstützung jeder Funktion, die ich parallel abbilden möchte, vermeiden?

Wie gehen erfahrene "Multiprocessing-Profis" damit um?

aktualisieren: Beachten Sie, dass ich bei der Verarbeitung viel größeren Arrays tatsächlich interessiert bin, so Variationen der oben dem src Beize jeden Anruf/Iteration sind nicht annähernd so gut wie diejenigen es welche Gabel in die Arbeitsprozesse Becken.

+0

Ich bin kein erfahrener Profi oder etwas Multiprozessing, aber lassen Sie mich Ihnen fragen, warum können Sie nicht mach einfach pool.map (process, product ([src], range (100))) und ändere die Prozessfunktion um beide Variablen als args zu akzeptieren? Ist das auch sehr ineffizient? – luke14free

+0

@ luke14free: Ja, das würde das src-Array bei jedem Aufruf ersetzen, und ich bin eigentlich an viel größeren Daten/Arrays interessiert als die im obigen Beispielcode, also nicht ideal. Mit dem Prozesspool wird der Zustand, der an dem Punkt eingerichtet wird, an dem der Pool erstellt wird, in die Worker-Prozesse gespalten und steht für sie zur Verfügung, um "kostenlos" zu lesen. Die Idee würde helfen, zu vermeiden, dass kleinere "Kontrollvariablen" (z. B. Flags) in globale Variablen gesetzt werden, danke. – timday

Antwort

5

Sie immer eine aufrufbare Objekt wie dies passieren konnte, dann kann das Objekt auf den freigegebenen Zustand Containe:

from multiprocessing import Pool 
import numpy as np 

class RowProcessor(object): 
    def __init__(self, src): 
     self.__src = src 
    def __call__(self, row): 
     return np.sum(self.__src[row]) 

def main(): 
    src=np.ones((100,100)) 
    p = RowProcessor(src) 

    pool=Pool(processes=16) 
    rows = pool.map(p, range(100)) 
    print rows 

if __name__ == "__main__": 
    main() 
+0

Sieht interessant aus ... gibt diesem Stil einen Versuch und meldet sich zurück ... – timday

+0

Yup funktioniert sehr gut dank; Tschüss Globals. Normalerweise würde ich länger warten, bevor ich eine Lösung akzeptiere, um zu sehen, ob noch etwas anderes auftaucht, aber das ist perfekt. Ich hatte schon vorher Klassen für dieses Problem ausprobiert und hatte keinen Erfolg; scheint, dass Callable den Unterschied macht. – timday

+2

Wäre es nicht pickle die aufrufbar und Sie sind zurück auf Platz eins? –

Verwandte Themen