为什么Python需要双倍的RAM才能读取文件?

时间:2016-03-30 19:42:58

标签: python

我正在阅读大小为24 GB的文件。我正在使用

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

似乎在读取行时,它总是使用〜应该需要的RAM量的两倍。它使用大约50 GB作为我当前的脚本(在它跳到50之后再回到28)但是每次我使用这种行来读取Python中的文件时它通常使用双倍文件大小在下降到我期望的大小之前。

知道为什么会这样或者我怎么能避免它?

6 个答案:

答案 0 :(得分:2)

RAM使用:Filesize * 1:将整个文件读入内存

open(fname).read()

RAM使用文件大小* 2:在列表中分配足够的空间以拆分换行符

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

此操作完成后,RAM使用量将下降至约Filesize * 1,因为不再需要该文件的全文,并且可以对其进行垃圾回收。

如果您不需要同时使用该文件的全文,并且只在线上操作,那么只需遍历该文件

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

答案 1 :(得分:0)

如果文件包含25Gb的数据,则file_handle.read()将返回大小为25Gb的字符串。拆分该字符串时,您将创建一个列表,该列表包含最多可添加25Gb数据的字符串(以及每个字符串的额外字符串开销)。所以你最终使用了大约两倍的内存。

垃圾收集器几乎可以立即获得大字符串,使得新的python对象可以占用内存,但这并不意味着内存完全被释放到操作系统(由于python中的优化和#39;内存分配器)。

更好的方法是一次累积一个行列表:

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

你只能在 1 的时间内从文件中保存大约一行内存,这样你的内存使用将主要只是存储列表的内存。

1 这并不完全正确... pythons内部线路缓冲在任何给定时间缓冲都可能有几kb的数据... < / p>

当然,可能还有迭代处理文件的选项:

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

答案 2 :(得分:0)

我的猜测是read返回整个文件的字符串,在从splitlines返回列表之前不会对其进行垃圾回收。如果需要内存中的文件,请尝试readlines方法:

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

答案 3 :(得分: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()

答案 4 :(得分:0)

read()返回单个str,其中包含整个文件数据。 splitlines正在使用相同的数据返回list lines。在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')

避免一次存储两行以上。

答案 5 :(得分:0)

您使用以下内容将整个文件读入内存:

open(fname).read()

在第二步中,您使用.splitlines()从此字符串创建列表。 在此期间,字符串保留在内存中,但您复制了部分内容 字符串逐行进入列表。只有在你完成创建后 列表,字符串可以被垃圾收集。所以在这段时间你会存储 所有信息两次,因此需要两倍的内存。

您可以使用open(fname).readlines()或逐行阅读文件以减少 内存占用。