2011-11-23 10 views
5

Sto cercando di elaborare il contenuto di un tarfile usando multiprocessing.Pool. Sono in grado di utilizzare con successo l'implementazione ThreadPool all'interno del modulo multiprocessing, ma vorrei essere in grado di utilizzare processi anziché thread in quanto sarebbe probabilmente più veloce ed eliminare alcune modifiche apportate a Matplotlib per gestire l'ambiente multithread. Sto ottenendo un errore che ho il sospetto è legato a processi che non condividono lo spazio di indirizzi, ma non sono sicuro di come risolvere il problema:Come posso elaborare un tarfile con un pool di multiprocessing Python?

Traceback (most recent call last): 
    File "test_tarfile.py", line 32, in <module> 
    test_multiproc() 
    File "test_tarfile.py", line 24, in test_multiproc 
    pool.map(read_file, files) 
    File "/ldata/whitcomb/epd-7.1-2-rh5-x86_64/lib/python2.7/multiprocessing/pool.py", line 225, in map 
    return self.map_async(func, iterable, chunksize).get() 
    File "/ldata/whitcomb/epd-7.1-2-rh5-x86_64/lib/python2.7/multiprocessing/pool.py", line 522, in get 
    raise self._value 
ValueError: I/O operation on closed file 

Il programma attuale è più complicato, ma questo è un esempio di quello sto facendo che riproduce l'errore:

from multiprocessing.pool import ThreadPool, Pool 
import StringIO 
import tarfile 

def write_tar(): 
    tar = tarfile.open('test.tar', 'w') 
    contents = 'line1' 
    info = tarfile.TarInfo('file1.txt') 
    info.size = len(contents) 
    tar.addfile(info, StringIO.StringIO(contents)) 
    tar.close() 

def test_multithread(): 
    tar = tarfile.open('test.tar') 
    files = [tar.extractfile(member) for member in tar.getmembers()] 
    pool = ThreadPool(processes=1) 
    pool.map(read_file, files) 
    tar.close() 

def test_multiproc(): 
    tar = tarfile.open('test.tar') 
    files = [tar.extractfile(member) for member in tar.getmembers()] 
    pool = Pool(processes=1) 
    pool.map(read_file, files) 
    tar.close() 

def read_file(f): 
    print f.read() 

write_tar() 
test_multithread() 
test_multiproc() 

ho il sospetto che il qualcosa che non va quando l'oggetto TarInfo viene passato l'altro processo, ma il genitore TarFile non è, ma non sono sicuro come risolvere il problema in il caso multiprocesso. Posso farlo senza dover estrarre i file dal tarball e scriverli sul disco?

risposta

5

Lei non è passando un oggetto TarInfo in altro processo, si sta passando il risultato della tar.extractfile(member) nell'altro processo in cui member è un oggetto TarInfo. Il metodo extractfile(...) restituisce un oggetto simile a un file che ha, tra le altre cose, un metodo read() che opera sul file tar originale che hai aperto con tar = tarfile.open('test.tar').

Tuttavia, non è possibile utilizzare un file aperto da un processo in un altro processo, è necessario riaprire il file. Ho sostituito il tuo test_multiproc() con questo:

def test_multiproc(): 
    tar = tarfile.open('test.tar') 
    files = [name for name in tar.getnames()] 
    pool = Pool(processes=1) 
    result = pool.map(read_file2, files) 
    tar.close() 

e ha aggiunto questo:

def read_file2(name): 
    t2 = tarfile.open('test.tar') 
    print t2.extractfile(name).read() 
    t2.close() 

e sono stato in grado di ottenere il codice di lavoro.

+0

Supporto Windows: 'se nome == '__main__': test_multiproc()'. Non c'è fork in Windows, quindi il modulo viene importato nel nuovo processo inizialmente con il nome "__parents_main __", e quindi il nome viene cambiato in "__main __". Quindi puoi proteggere le dichiarazioni che non vuoi eseguire nei processi figli usando un blocco 'if'. – eryksun

+0

Funziona, ma mi richiede di riaprire il tarfile in ogni processo. C'è qualche altro rimedio che consentirebbe l'accesso in sola lettura a un descrittore di file tra processi? –

+0

Ho finito per impostare un flag per la pre-lettura dei dati prima che i processi multipli inizino. Grazie! –

Problemi correlati