2009-02-04 78 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 ...