2012-04-14 9 views
7

Questo (ad esempio enormemente semplificato) funziona bene (Python 2.6.6, Debian Squeeze):Modelli di utilizzo alternativi per il multiprocesso di Python che evita la proliferazione dello stato globale?

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() 

tuttavia, dopo anni di essere insegnato stato globale male !!!, tutti i miei istinti mi dicono io davvero preferirei scriverò qualcosa di più vicino:

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() 

ma, naturalmente, che non funziona (si blocca fino incapace di salamoia qualcosa).

L'esempio qui è banale, ma quando si aggiungono più funzioni "di processo" e ognuna di queste dipende da più ingressi aggiuntivi ... beh, tutto diventa un po 'reminescente di qualcosa scritto in BASIC 30 anni fa . Cercare di utilizzare le classi per aggregare almeno lo stato con le funzioni appropriate sembra una soluzione ovvia, ma in pratica lo doesn't seem to be that easy.

C'è qualche schema o stile consigliato per l'utilizzo di multiprocessing.pool che eviterà la proliferazione dello stato globale per supportare ogni funzione su cui voglio eseguire la mappatura parallela?

In che modo i "professionisti multiprocessing" esperti si occupano di questo?

Aggiornamento: Notare che sono effettivamente interessati nella lavorazione molto array più grandi, così variazioni sul sopra del quale sottaceto src ogni chiamata/iterazione non sono altrettanto buono come quelli che forcella in processi di lavoro del pool.

+0

Io non sono un esperto multiprocessing pro o altro, ma lasciate che vi chiedo perché non si può semplicemente fare pool.map (processo, prodotto ([src], intervallo (100))) e cambiare la funzione del processo per accettare entrambe le variabili come argomenti? Anche questo è altamente inefficiente? – luke14free

+0

@ luke14free: Sì, questo avrebbe messo sottosopra l'array src per ogni chiamata, e in realtà sono interessato a matrici/dati molto più grandi di quelli nel codice di esempio qui sopra, quindi non ideale. Con il pool di processi, qualsiasi stato viene impostato nel punto in cui il pool viene creato viene biforcato nei processi di lavoro e disponibile per essere letto "gratuitamente". L'idea contribuirebbe a evitare di inserire in "globals" anche uno stato di "variabili di controllo" minori (ad esempio bandiere), grazie. – timday

risposta

5

Si può sempre passare un oggetto richiamabile come questo, allora l'oggetto può Containe stato condiviso:

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

Sembra interessante ... darò a questo stile una prova e riferire ... – timday

+0

Yup funziona molto bene grazie; ciao ciao globali. Normalmente aspetterei più tempo prima di accettare una soluzione per vedere se qualcos'altro si presenta ma questo è perfetto. Avevo già provato le lezioni per questo problema e non avevo avuto alcun successo; sembra che callable faccia la differenza. – timday

+2

Non vorrebbe decimare il callable e torni al punto di partenza? –

Problemi correlati