2013-02-07 39 views
8

ho writen un programma che può essere riassunta come segue:Python utilizzo della memoria multiprocessing

def loadHugeData(): 
    #load it 
    return data 

def processHugeData(data, res_queue): 
    for item in data: 
     #process it 
     res_queue.put(result) 
    res_queue.put("END") 

def writeOutput(outFile, res_queue): 
    with open(outFile, 'w') as f 
     res=res_queue.get() 
     while res!='END': 
      f.write(res) 
      res=res_queue.get() 

res_queue = multiprocessing.Queue() 

if __name__ == '__main__': 
    data=loadHugeData() 
    p = multiprocessing.Process(target=writeOutput, args=(outFile, res_queue)) 
    p.start() 
    processHugeData(data, res_queue) 
    p.join() 

Il vero codice (soprattutto'writeOutput() ') è molto più complicato. 'writeOutput() 'utilizza solo questi valori che assume come argomenti (ovvero non fa riferimento a hadata')

In pratica carica un enorme set di dati in memoria e lo elabora. La scrittura dell'output è delegata a un processo secondario (scrive in più file in realtà e ciò richiede molto tempo). Quindi, ogni volta che viene elaborato un elemento di dati, viene inviato al processo secondario tramite res_queue che a sua volta scrive il risultato in file, se necessario.

Il processo secondario non ha bisogno di accedere, leggere o modificare i dati caricati da "loadHugeData()" in alcun modo. Il processo secondario deve solo utilizzare ciò che il processo principale invia tramite'res_queue'. E questo mi porta al mio problema e alla mia domanda.

Mi sembra che il processo secondario ottenga la copia dell'enorme set di dati (quando si controlla l'utilizzo della memoria con'top'). È vero? E se è così allora come posso evitare id (usando essenzialmente la doppia memoria)?

Sto usando Python 2.6 e il programma è in esecuzione su linux.

+0

Riesci a ristrutturare il codice per utilizzare gli iteratori invece di caricare tutto il carico di HugeData? Sembrerebbe che si potrebbe se è come sembra caricare/elaborare/accodare/dequeue/scrivere – sotapme

+0

Il "hugeData" è purtroppo un file txt separato da tabulazioni che contiene fondamentalmente un array sparse. E ho bisogno di "accesso casuale" a questi dati in base al numero di linea durante l'elaborazione. Pertanto caricarlo in memoria (con ottimizzazioni specifiche per array sparsi) rende l'elaborazione molto più veloce. – FableBlaze

+0

Potrebbe essere eccessivamente ingegneristico suggerire di usare qualcosa come '[beanstalkd] (https://github.com/earl/beanstalkc/blob/master/TUTORIAL.mkd) per fare l'integrazione del processo ma sarebbe interessante sapere se ha aiutato/ridimensionato/perfomed. Come al solito i problemi degli altri sono sempre più interessanti. – sotapme

risposta

13

Il modulo multiprocessing si basa in modo efficace sulla chiamata di sistema fork che crea una copia del processo corrente. Poiché si caricano i dati enormi prima di fork (o si crea lo multiprocessing.Process), il processo figlio eredita una copia dei dati.

Tuttavia, se il sistema operativo in esecuzione su implementa COW (copy-on-write), ci sarà solo una copia dei dati nella memoria fisica a meno che non si modifichino i dati nel processo padre o figlio (sia genitore che figlio saranno condividere le stesse pagine di memoria fisica, anche se in spazi di indirizzi virtuali diversi); e anche in questo caso, la memoria aggiuntiva verrà assegnata solo per le modifiche (negli incrementi pagesize).

È possibile evitare questa situazione chiamando multiprocessing.Process prima di caricare i dati enormi. Quindi le allocazioni di memoria aggiuntive non si rifletteranno nel processo figlio quando si caricano i dati nel genitore.

+1

Più veloce di me ben fatto. Linux è COW quindi nel momento in cui il processo genitore scrive sui dati, i dati saranno duplicati. Se il processo genitore legge solo i dati, ci sarà solo un'istanza dei dati ** BUT ** top (sono quasi sicuro) mostrerà i dati come appartenenti a entrambi i processi. meminfo dovrebbe fornire numeri più precisi sull'uso della memoria. –

+0

Infatti. Penso che il sistema operativo più comune sia COW in questi giorni (stavo solo cercando di essere il più generico possibile). Grande funzionalità, ma spesso causa confusione nell'interpretazione dell'output degli strumenti di reporting della memoria basati sui processi (cioè top, ps, ecc ...).'meminfo' su Linux riporterà correttamente come' pmap' su Solaris; nessuna idea su Windows :) – isedev

+5

Nota anche che ogni oggetto Python contiene un conteggio dei riferimenti che viene modificato ogni volta che si accede all'oggetto. Quindi, solo la lettura di una struttura dati può far sì che la COW copi. –