【问题标题】:Reading a large file in python在python中读取一个大文件
【发布时间】:2013-11-05 18:44:38
【问题描述】:

我有一个“不太”的大文件 (~2.2GB),我正在尝试读取和处理它...

graph = defaultdict(dict)
error = open("error.txt","w")
print "Reading file"
with open("final_edge_list.txt","r") as f:
    for line in f:
        try:
            line = line.rstrip(os.linesep)
            tokens = line.split("\t")
            if len(tokens)==3:
                src = long(tokens[0])
                destination = long(tokens[1])
                weight = float(tokens[2])
                #tup1 = (destination,weight)
                #tup2 = (src,weight)
                graph[src][destination] = weight
                graph[destination][src] = weight
            else:
                print "error ", line 
                error.write(line+"\n")
        except Exception, e:
            string = str(Exception) + " " + str(e) +"==> "+ line +"\n"
            error.write(string)
            continue

我是不是做错了什么??

已经过了一个小时……因为代码正在读取文件……(它仍在读取……)

并且跟踪内存使用量已经是 20GB.. 为什么要花这么多时间和内存??

【问题讨论】:

  • 哦,好吧,至少你没有像我前段时间那样出现 50G 内存泄漏 :D 就是说,有没有看过像 NetworkX 这样的图形处理库?他们可能更有效率!
  • 注释掉 dict-building 代码,看看读取文件需要多长时间。我的猜测是它会很快运行。我的另一个猜测与@DSM 的相同:您可能正在创建大量的字典。
  • 我没有足够的信心将此作为答案发布,但您不应该先使用 f.readlines() 吗?
  • @Dunno:不会。readlines() 会使内存问题变得更糟:它会在循环开始之前将整个文件读入内存,而for line in f: 只会将单行放入内存。跨度>
  • @bukzor:我只是认为如果不先使用readlines()for line in f: 将无法正常工作。无论如何,谢谢,没关系。

标签: python


【解决方案1】:

要大致了解内存的去向,您可以使用gc.get_objects 函数。将上面的代码封装在 make_graph() 函数中(无论如何这是最佳实践),然后使用 KeyboardInterrupt 异常处理程序封装对该函数的调用,该异常处理程序将 gc 数据打印到文件中。

def main():
    try:
        make_graph()
    except KeyboardInterrupt:
        write_gc()

def write_gc():
    from os.path import exists
    fname = 'gc.log.%i'
    i = 0
    while exists(fname % i):
        i += 1
    fname = fname % i
    with open(fname, 'w') as f:
        from pprint import pformat
        from gc import get_objects
        f.write(pformat(get_objects())


if __name__ == '__main__':
    main()

现在,每当您 ctrl+c 程序时,您都会得到一个新的 gc.log。给定一些示例,您应该能够看到内存问题。

【讨论】:

  • make_graph() 来自哪里?
  • @Dualinity:为方便起见复制粘贴:将上面的代码包装在 make_graph() 函数中(无论如何这是最佳实践)...
  • 你不应该在函数中使用导入。只需将它们放在顶层即可。
  • @bukzor 我的意思是,我不明白它是什么?它属于一个包吗?
  • @Dualinity 在这个答案的开头,bukzor 说“将上面的代码包装在make_graph() 函数中”。 IE。 make_graph() 定义为将问题中的代码复制粘贴到函数内。
【解决方案2】:

你可以做一些事情:

  1. 在数据子集上运行您的代码。测量所需时间。外推到数据的完整大小。这将让您估计它会运行多长时间。

    计数器 = 0 使用 open("final_edge_list.txt","r") 作为 f: 对于 f 中的行: 计数器 += 1 如果计数器 == 200000: 休息 尝试: ...

    在 1M 行上,它在我的机器上运行约 8 秒,因此对于约 100M 行的 2.2Gb 文件,它假设运行约 15 分钟。不过,一旦你超过了可用内存,它就不再存在了。

  2. 你的图看起来是对称的

    graph[src][destination] = weight
    graph[destination][src] = weight
    

    在您的图形处理代码中使用graph 的对称性,将内存使用量减少一半。

  3. 使用数据子集对您的代码运行分析器,看看那里会发生什么。最简单的就是运行

    python -m cProfile --sort cumulative youprogram.py
    

    有一篇关于速度和内存分析器的好文章:http://www.huyng.com/posts/python-performance-analysis/

【讨论】:

    【解决方案3】:

    与其他编程语言相比,Python 的数值类型占用了大量内存。对于我的设置,每个数字似乎是 24 个字节:

    >>> import sys
    >>> sys.getsizeof(int())
    24
    >>> sys.getsizeof(float())
    24
    

    鉴于您在该 2.2 GB 输入文件中有数亿行,报告的内存消耗应该不会出现意外。

    补充一点,Python 解释器的某些版本(包括 CPython 2.6)are known for keeping so called free lists for allocation performance,尤其是 intfloat 类型的对象。分配后,在您的进程终止之前,该内存将不会返回给操作系统。也看看我第一次发现这个问题时发布的这个问题:

    解决此问题的建议包括:

    • 使用子进程进行内存消耗计算,例如,基于 multiprocessing 模块
    • 使用在 C 中实现功能的库,例如 numpy、pandas
    • 使用其他解释器,例如 PyPy

    【讨论】:

      【解决方案4】:
      • 你不需要graph是defaultdict(dict),而是用户dict; graph[src, destination] = weightgraph[destination, src] = weight 可以。或者只有其中之一。
      • 为减少内存使用,请尝试将生成的数据集存储在 scipy.sparse 矩阵中,它消耗的内存更少并且可能会被压缩。
      • 之后您打算如何处理您的节点列表?

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-13
        • 2020-04-28
        • 2019-04-04
        • 2012-07-14
        • 2021-11-29
        • 1970-01-01
        • 2021-03-13
        • 2017-09-15
        相关资源
        最近更新 更多