2012-01-06 21 views
7

Mi dispiace se questo è troppo semplice per alcune persone, ma non riesco ancora a ottenere il trucco con il multiprocessing di Python. Ho letto
http://docs.python.org/dev/library/multiprocessing
http://pymotw.com/2/multiprocessing/basics.html e molti altri tutorial ed esempi che google mi dà ... molti di loro anche da qui.Multiprocessing di Python per processi paralleli

Bene, la mia situazione è che devo calcolare molte matrici numpy e ho bisogno di memorizzarle in una singola matrice numpy in seguito. Diciamo che voglio usare 20 core (o che posso usare 20 core) ma non sono riuscito a utilizzare correttamente la risorsa del pool poiché mantiene i processi attivi finché il pool "muore". Così ho pensato di fare qualcosa di simile:

from multiprocessing import Process, Queue 
import numpy as np 

def f(q,i): 
    q.put(np.zeros((4,4))) 

if __name__ == '__main__': 
    q = Queue() 
    for i in range(30): 
      p = Process(target=f, args=(q,)) 
      p.start() 
      p.join() 
    result = q.get() 
    while q.empty() == False: 
      result += q.get() 
    print result 

ma poi sembra che i processi non vengono eseguiti in parallelo, ma corrono in sequenza (per favore correggetemi se sbaglio) e non so se muoiono dopo aver fatto il loro calcolo (quindi per più di 20 processi quelli che hanno fatto la loro parte lasciano il core libero per un altro processo). Inoltre, per un numero molto grande (diciamo 100.000), l'archiviazione di tutte quelle matrici (che possono essere anche molto grandi) in una coda utilizzerà molta memoria, rendendo il codice inutile poiché l'idea è di mettere ogni risultato su ogni iterazione nel risultato finale, come usare un lock (e i suoi metodi acquire() e release()), ma se questo codice non è per l'elaborazione parallela, il blocco è inutile anche ...

Spero che qualcuno possa aiutare me.

Grazie in anticipo!

risposta

14

Si è corretto, si stanno eseguendo in sequenza nel proprio esempio.

p.join() causa il blocco del thread corrente fino al completamento dell'esecuzione. O vuoi unire i tuoi processi singolarmente al di fuori del tuo ciclo for (ad esempio, memorizzandoli in un elenco e quindi eseguendoli in iterazione) o utilizzare qualcosa come numpy.Pool e apply_async con un callback. Questo ti permetterà anche di aggiungerlo direttamente ai tuoi risultati piuttosto che tenere gli oggetti intorno.

Ad esempio:

def f(i): 
    return i*np.identity(4) 

if __name__ == '__main__': 
    p=Pool(5) 
    result = np.zeros((4,4)) 
    def adder(value): 
     global result 
     result += value 

    for i in range(30): 
     p.apply_async(f, args=(i,), callback=adder) 
    p.close() 
    p.join() 
    print result 

Chiusura e poi unirsi alla piscina alla fine assicura che i processi del pool hanno completato e l'oggetto result è finito di essere calcolato. Puoi anche investigare usando Pool.imap come soluzione al tuo problema. Quel particolare soluzione sarebbe simile a questa:

if __name__ == '__main__': 
    p=Pool(5) 
    result = np.zeros((4,4)) 

    im = p.imap_unordered(f, range(30), chunksize=5) 

    for x in im: 
     result += x 

    print result 

Questo è più pulita per la vostra situazione specifica, ma non può essere per tutto ciò che stanno in ultima analisi, cercando di fare.

Per quanto riguarda la memorizzazione di tutti i risultati vari, se ho capito la tua domanda, puoi semplicemente aggiungerla in un risultato nel metodo di richiamata (come sopra) o articolo alla volta usando imap/imap_unordered (che memorizza ancora i risultati, ma lo cancellerai man mano che viene generato). Quindi non ha bisogno di essere conservato più a lungo di quanto ci vuole per aggiungere al risultato.

+0

Grazie per la risposta! Capisco la prima soluzione in più, e trovo la callback estremamente utile poiché imap_unordered sembra archiviare tutti i risultati, ed è quello che non vorrei fare per non mangiare memoria. Per quanto riguarda il pool, non sono sicuro (a causa di ciò che ho letto sull'attributo maxtasksperchild) che se ho processori "x", i processi "3x" verranno eseguiti poiché i "primi" processi "x" non muoiono.Non sono nemmeno sicuro se la memoria allocata per i primi processi "x" sia libera dopo il callback. Chiedo di non "bloccare" il mio pc quando si utilizzano molte più grandi matrici – Carlos

+0

Oh! Penso che ora capisco: gli operai sono vivi finchè la piscina è viva, ma non appena finiscono un processo liberano le risorse e poi prendono il processo successivo e fanno il calcolo ... È così? – Carlos

+0

Sì, questo è tutto. Non mi preoccuperei troppo di "Pool" o di trovare un sostituto a meno che non si disponga di dati di profilazione che indicano che si tratta di un problema. Ci sono ottimizzazioni che puoi fare, ma finché non avrai dimostrato che c'è un problema nel tuo sistema reale, la maggior parte di esse non vale la pena. –

Problemi correlati