2015-12-18 98 views
4

在我的代碼中有一個函數應該讀取文件。每個文件大約8M,但是讀取速度太低,並且爲了改進我使用多處理.sadly,它似乎它被阻止了。我想知道是否有任何方法可以幫助解決這個問題並提高閱讀速度?python多處理讀取文件花費太多時間

我的代碼如下:

import multiprocessing as mp 
import json 
import os 

def gainOneFile(filename): 

    file_from = open(filename) 
    json_str = file_from.read() 
    temp = json.loads(json_str) 
    print "load:",filename," len ",len(temp) 
    file_from.close() 
    return temp 

def gainSortedArr(path): 
    arr = [] 
    pool = mp.Pool(4) 
    for i in xrange(1,40): 
     abs_from_filename = os.path.join(path, "outputDict"+str(i)) 
     result = pool.apply_async(gainOneFile,(abs_from_filename,)) 
     arr.append(result.get()) 

    pool.close() 
    pool.join()            
    arr = sorted(arr,key = lambda dic:len(dic)) 

    return arr 

和呼叫功能:

whole_arr = gainSortedArr("sortKeyOut/") 
+0

似乎問題是在主進程中收集數據期間的序列化/反序列化。 – newtover

+1

通過跳過中間字符串...'temp = json.load(file_from)',您將獲得適度的增益。 – tdelaney

+0

這裏沒有mp優勢。您在子進程中解碼JSON,但在返回父進程時必須重新序列化和反序列化。它可能慢於在一個文件中完成所有操作。在這裏,用低並行計算的轉換成本很高。 – tdelaney

回答

4

你有幾個問題。首先,你不是並行化的。你這樣做:

result = pool.apply_async(gainOneFile,(abs_from_filename,)) 
arr.append(result.get()) 

了個遍,分派任務,然後立即打電話.get()它等待它完成你發送的任何額外任務前;你永遠不會有一個以上的員工同時運行。將所有結果存儲在不調用.get()的情況下,稍後再調用.get()。或者只是使用Pool.map或相關方法,並省去手動個人結果管理中的一些麻煩,例如(使用imap_unordered,以儘量減少開銷,因爲你只是排序反正):

# Make generator of paths to load 
paths = (os.path.join(path, "outputDict"+str(i)) for i in xrange(1, 40)) 
# Load them all in parallel, and sort the results by length (lambda is redundant) 
arr = sorted(pool.imap_unordered(gainOneFile, paths), key=len) 

其次,multiprocessing有鹹菜和unpickle所有參數和返回主進程和工人之間發送的值,而這一切都送過來管道這會引起系統調用開銷。由於您的文件系統不太可能通過並行讀取獲得顯着的速度,因此很可能是淨損失,而不是增益。

可能通過切換到基於線程池可以得到一點提升;將import更改爲import multiprocessing.dummy as mp,您將獲得以線程形式實現的Pool版本;他們並沒有圍繞CPython GIL工作,但由於這些代碼幾乎可以肯定是I/O綁定的,所以這並不重要,並且它消除了酸洗和拆卸以及涉及工作人員通信的IPC。最後,如果您在UNIX系統上使用Python 3.3或更高版本,則可以讓操作系統通過更積極地將文件拖入系統緩存中來幫助您。如果可以打開該文件,然後在文件描述符使用os.posix_fadvise.fileno()上的文件對象)與任何WILLNEEDSEQUENTIAL當您通過積極預取文件數據您請求之前,在以後的某個點上的文件讀取可能提高讀取性能它。

+0

我會完全忽略讀數,只是映射文件。 –

+0

@ IgnacioVazquez-Abrams:在很多情況下,我也是如此,但那是我不想打開的其他蠕蟲。這也不總是最好的方法; 32位系統會遇到大文件的問題,在文件被解析爲JSON的情況下,在Python 3中,'mmap'對象只能用作類似字節的對象,而不能用作str和json。在Python 3上只能從'str'加載;你仍然需要從'mmap'中讀取和解碼,所以你從中獲得的很少。即使在Py2上,如果'mmap'與'loads'一起工作,我懷疑它最終會被解碼,所以再次沒有真正的節約。 – ShadowRanger

+0

不要忘記,除非您從多個磁盤讀取數據,否則這將會受到IO限制,因此從同一磁盤讀取多個文件(尤其是在旋轉的情況下)可能會影響性能。 –