2009-02-04 79 views
4

我有許多大型(〜100 Mb)文件,我經常處理這些文件。雖然我試圖在處理過程中刪除不需要的數據結構,但內存消耗有點過高。我想知道是否有辦法有效地處理大數據,例如:大型數據結構操作/處理中的內存使用

def read(self, filename): 
    fc = read_100_mb_file(filename) 
    self.process(fc) 
def process(self, content): 
    # do some processing of file content 

是否有數據結構的重複?使用像self.fc這樣的類屬性是否更有效率?

什麼時候應該使用垃圾回收?我知道有關gc模塊,但是我是否在例如del fc之後調用它?

更新
p.s. 100 Mb本身不是問題。但浮動轉換,進一步處理添加顯着更多的工作集和虛擬大小(我在Windows上)。

+0

文件中的哪些內容?處理過程在做什麼? – 2009-02-04 19:38:21

+0

逗號分隔的時間序列,我減少到一些可以理解的總結變量 – SilentGhost 2009-02-04 19:43:35

+0

你能更具體一點,也許發表一個小例子? – oefe 2009-02-04 21:45:54

回答

7

我建議看看在Python中使用生成器的presentation by David Beazley。這項技術可以讓您處理大量數據,並且可以快速完成複雜的處理,而不會浪費您的內存使用。海事組織,訣竅是不盡可能有效地在內存中保存大量數據;訣竅是避免同時將大量數據加載到內存中。

3

在開始在垃圾回收器上撕掉你的頭髮之前,你可能可以通過使用內存映射文件對象來避免100mb命中加載整個文件到內存中。請參閱mmap模塊。

3

不要每次讀取整個100兆文件。一次使用流處理一點點。看看這篇博客文章,討論如何處理大型csv和xml文件。 http://lethain.com/entry/2009/jan/22/handling-very-large-csv-and-xml-files-in-python/

下面是本文代碼示例。

from __future__ import with_statement # for python 2.5 

with open('data.in','r') as fin: 
    with open('data.out','w') as fout: 
     for line in fin: 
      fout.write(','.join(line.split(' '))) 
2

所以,從你的意見,我認爲你的文件看起來是這樣的:

item1,item2,item3,item4,item5,item6,item7,...,itemn 

,你所有的某種組合功能的重複申請降低到一個值。作爲一個解決方案,一次只能讀取單個值:

def read_values(f): 
    buf = [] 
    while True: 
     c = f.read(1) 
     if c == ",": 
      yield parse("".join(buf)) 
      buf = [] 
     elif c == "": 
      yield parse("".join(buf)) 
      return 
     else: 
      buf.append(c) 

with open("some_file", "r") as f: 
    agg = initial 
    for v in read_values(f): 
     agg = combine(agg, v) 

這樣,內存消耗保持不變,除非agg生長在時間。

  1. 提供initialparsecombine
  2. 適當的實現不讀取文件逐字節,但在一個固定的緩衝區讀取,從緩衝區分析和了解更多,你需要它
  3. 這基本上是內置的reduce函數所做的,但爲了清晰起見,我在這裏使用了明確的for循環。下面是使用reduce同樣的事情:

    with open("some_file", "r") as f: 
        agg = reduce(combine, read_values(f), initial) 
    

我希望我正確地解釋你的問題。

0

首先,不要碰垃圾收集器。這不是問題,也不是解決方案。

聽起來你真正遇到的問題不在於讀取文件,而是在處理文件時分配的數據結構。 使用 del進行排序以刪除處理期間不再需要的結構。另外,您可能會考慮使用元帥將部分處理的數據轉儲到磁盤,同時處理下一個100MB的輸入文件。

對於文件讀取,基本上有兩種選擇:unix風格的文件作爲流或內存映射文件。對於基於流的文件,默認的Python文件對象已經被緩衝,所以最簡單的代碼也可能是最有效的:

 
    with open("filename", "r") as f: 
    for line in f: 
     # do something with a line of the files 

或者,你可以使用f.read([大小])讀取的塊文件。但是,通常您通過多線程處理腳本的處理部分來獲得CPU性能,以便您可以同時讀取和處理。但它不利於內存使用;實際上,它使用更多的內存。

另一種選擇是mmap的,它看起來像這樣:

 
    with open("filename", "r+") as f: 
    map = mmap.mmap(f.fileno(), 0) 
    line = map.readline() 
    while line != '': 
     # process a line 
     line = map.readline() 

這有時優於流,但它也不會提高內存的使用情況。

0

在您的示例代碼中,數據存儲在fc變量中。如果你沒有保留對fc的引用,當方法結束時,你的整個文件內容將從內存中刪除。

如果他們不是,那麼你保持參考某處。也許參考正在創建read_100_mb_file,也許在process。如果沒有參考,CPython實現將立即釋放它。

有一些工具來幫助你尋找到這個引用,guppydowserpysizer ...