2011-11-23 85 views
5

我正在嘗試使用multiprocessing.Pool來處理tarfile的內容。我能夠在多處理模塊中成功使用ThreadPool實現,但希望能夠使用進程而不是線程,因爲它可能會更快,並且消除了Matplotlib處理多線程環境所做的一些更改。我收到我懷疑是與不共享地址空間的進程中出現錯誤,但我不知道如何解決它:我該如何處理一個Python多處理池的tar文件?

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 

實際的程序較爲複雜,但這是一個例子什麼我做了重現錯誤:

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

我懷疑,當TarInfo對象傳遞到另一個過程,但家長TarFile不是什麼是錯的,但我不知道如何解決它在多進程的情況。我可以做到這一點,而無需從tarball中提取文件並將它們寫入磁盤?

回答

5

你不能傳遞一個TarInfo對象到另一個過程中,要傳遞的tar.extractfile(member)結果到另一個過程,其中memberTarInfo對象。 extractfile(...)方法返回一個類似文件的對象,其中包含一個read()方法,該方法對用tar = tarfile.open('test.tar')打開的原始tar文件進行操作。

但是,您不能在另一個進程中使用來自某個進程的打開文件,必須重新打開該文件。我換成你test_multiproc()本:

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

,並將此:

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

,並能夠得到您的代碼工作。

+0

Windows支持:'if name =='__main__':test_multiproc()'。在Windows中沒有分支,因此模塊在名稱爲'__parents_main __'的名稱下被導入到新流程中,然後名稱被更改爲'__main __''。所以你可以使用'if'塊來防止你不想在子進程中運行的語句。 – eryksun

+0

這有效,但需要我在每個進程中重新打開tarfile。是否有任何其他解決方法允許在進程之間對文件描述符進行只讀訪問? –

+0

我最終設置了一個標誌,在多個進程分離之前預讀數據。謝謝! –