2016-03-30 43 views
-1

我正在閱讀的文件大小爲24 GB。我使用爲什麼Python需要雙倍的RAM來讀取文件?

lines = open(fname).read().splitlines() 

,似乎讀線時,它總是使用〜應需要的RAM雙量。它使用大約50 GB作爲我當前的腳本(在跳轉到50之後它會回落到28),但每次我使用這種類型的行讀取Python中的文件時,它通常會使用兩倍的文件大小,然後降低到一個大小我期望的。

任何想法爲什麼會發生這種情況,或者我可以如何避免它?

+2

是否有任何理由需要將整個文件保存在內存中? –

+0

因爲Python在內存中加載了'open(fname).read()'的結果,然後在其上運行'splitlines()'。 – Carpetsmoker

+1

你的代碼顯式地在內存中創建了一個巨大的字符串(open(fname).read()'),後來被'.splitlines()'分割成了單獨的行。在分割操作發生之前,無法收集巨大的字符串。任何你需要在內存中整個文件的原因? Python具有懶讀文件的機制。 –

回答

2

RAM用法:作品尺寸* 1:將整個文件讀入內存

open(fname).read() 

RAM使用作品尺寸* 2:分配足夠的空格列表中拆分換行符

open(fname).read().splitlines() 

此操作完成後,RAM使用率回落到大約F ilesize * 1,因爲該文件的全文不再需要,可以進行垃圾收集。


如果您不需要文件的全文一次,並且只在流水線作業,然後就在文件迭代

with open(filename) as f: 
    for line in f: 
     # do something 
0

如果文件包含25Gb的數據,則file_handle.read()將返回25Gb大小的字符串。當您拆分該字符串時,您將創建一個列表,其中包含可累計25Gb數據的字符串(以及每個字符串額外的字符串開銷)。所以你最終會使用大約兩倍的內存。

大字符串幾乎立即被垃圾收集器收割,使內存可用於新的python對象佔用,但這並不意味着內存已完全釋放到操作系統(由於python內存中的優化分配器)。

更好的方法是在一個時間積累行一個列表:

with open(filename) as f: 
    lines = list(f) 

你只持有約一個行從文件存儲在一個時間所以那麼你的內存使用將主要只是存儲列表的內存。

這是不完全正確......蟒蛇內部行緩衝可能會有數據的一對夫婦在KB緩存的任何給定的時間...

當然,也有可能是選項反覆處理文件:

with open(filename) as f: 
    for line in f: 
     process(line) 
0

我的猜測是,read返回整個文件,這是沒有收集到一個列表從splitlines返回垃圾的字符串。如果您需要在內存中的文件,嘗試readlines方法:

with open(fname) as f: 
    lines = f.readlines() 
0

read()試圖加載整個文件中記憶。使用開銷和緩衝區時,這可能會超過文件的大小。然後你將文件的內容分割成幾行,因爲python會爲每一行分配新的內存。

您的代碼可以重構爲使用readline()並逐行處理這些行嗎?這會減少程序一次使用的內存量。

with open(filename) as f: 
    for line in f: 
     # process a single line, maybe keeping some state elsewhere. 

然而,如果你仍然需要一次加載所有內存中的行,可以用readlines()代替:

with open(filename) as f: 
    lines = f.readlines() 
0

read()返回一個單一str在它整個文件數據。 splitlines正在用lineslist返回相同的數據。直到splitlines創建list之後,整個文件數據才被清理,因此您在短時間內存儲兩份數據副本。

如果你希望儘量減少這方面的開銷(現在仍然剝離新行),你可以嘗試:

with open(fname) as f: 
    lines = [line.rstrip('\r\n') for line in f] 

如果你能處理逐行(不需要全list一次),它甚至更好:

with open(fname) as f: 
    for line in f: 
     line = line.rstrip('\r\n') 

它避免了一次存儲兩行以上的行。

0

您與讀取整個文件到內存:

open(fname).read() 

在你從這個字符串.splitlines()創建列表的第二個步驟。 在此期間,字符串保留在內存中,但您將 字符串的各個部分逐行復制到列表中。只有在完成創建 列表後,字符串才能被垃圾收集。因此,在這段時間內,您將所有信息存儲兩次,因此需要存儲兩倍的內存。

您可以使用open(fname).readlines()或逐行讀取文件以減少內存佔用量。

相關問題