用Python读取大型二进制文件的最有效方法是什么

2 投票
3 回答
12266 浏览
提问于 2025-04-20 18:28

我有一个很大的文件(21GB),我想把它读入内存,然后传给一个子程序,这个子程序会帮我处理数据,我不需要干预。我现在用的是Python 2.6.6,运行在Centos 6.5上,所以我不能升级操作系统或Python。现在,我用的代码是

f = open(image_filename, "rb")
image_file_contents=f.read()
f.close()
transparent_subroutine ( image_file_contents )

但是这个速度很慢,大约需要15分钟。在我开始读取文件之前,我已经知道文件的大小,因为我调用了 os.stat( image_filename ).st_size

所以如果有必要的话,我可以提前分配一些内存。

谢谢

3 个回答

0

我知道我这个问题是九年前问的,不过在回顾这个问题时,我有了一些当时没有的想法。

答案其实很大程度上取决于你程序可用的内存大小。你的系统管理员可能会限制操作系统能给你分配的虚拟内存(通过一个叫做ulimit的设置,这个设置保存在/etc/security里),如果是这样的话,想要存储那么大的数据就会失败。不过,如果你的物理内存少于21GB(可能还有其他我不知道或者忘记的限制),那么在读取21GB数据时,程序就会开始出现页面错误。最开始,Linux的内存管理器会尝试从那些在内存中但目前不在使用的页面中调取数据。如果这样不行,内存管理器就会开始从硬盘中调取数据。通常情况下,访问内存的速度会少于10纳秒(使用现代的RAM)。当请求的虚拟页面不在当前使用的页面中,但在物理内存中存在时,这种情况叫做“干净的”页面错误,可能需要几微秒来处理。而“脏”的页面错误则是指请求的虚拟页面在物理内存中根本不存在,必须从硬盘中调入,这可能需要几毫秒。要对这些数字保持一点怀疑,因为有很多配置相关的因素会影响它们。

1

根据Dietrich的建议,我测量了一下,使用这种mmap技术处理一个1.7GB的输入文件,比一次性读取整个文件快了20%。

from zlib import adler32 as compute_cc

n_chunk = 1024**2
crc = 0
with open( fn ) as f:
  mm = mmap.mmap( f.fileno(), 0, prot = mmap.PROT_READ, flags = mmap.MAP_PRIVATE )
  while True:
    buf = mm.read( n_chunk )
    if not buf: break
    crc = compute_crc( buf, crc )
return crc
3

使用生成器

def generator(file_location):

    with open(file_location, 'rb') as entry:

        for chunk in iter(lambda: entry.read(1024 * 8), b''):

            yield chunk


go_to_streaming = generator(file_location) 

撰写回答