[编辑:此问题仅适用于32位系统。如果您的计算机、操作系统和python实现是64位的,那么mmap ing great files工作可靠,效率极高。]
我正在编写一个模块,其中包括允许按位读取访问文件。这些文件可能很大(数百GB),所以我编写了一个简单的类,让我把文件当作字符串处理,并隐藏所有的查找和读取。
在我写包装类的时候,我不知道mmap module。在阅读mmap的文档时,我认为“很好——这正是我所需要的,我将拿出我的代码并用mmap替换它。它可能更高效,删除代码总是很好的。”
问题是mmap不适用于大文件!这让我很惊讶,因为我认为这可能是最明显的应用。如果文件超过几GB,那么我得到一个EnvironmentError: [Errno 12] Cannot allocate memory
。这只在32位Python构建中发生,所以看起来地址空间用完了,但是我找不到任何关于此的文档。
我的代码是
f = open('somelargefile', 'rb')
map = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ)
所以我的问题是我是否遗漏了一些显而易见的东西?有没有办法让mmap在大文件上可移植地工作,或者我应该回到我的原始文件包装器?
更新:似乎有一种感觉,Python mmap应该具有与POSIX mmap相同的限制。为了更好地表达我的不满,这里有一个简单的类,它有mmap的一小部分功能。
import os
class Mmap(object):
def __init__(self, f):
"""Initialise with a file object."""
self.source = f
def __getitem__(self, key):
try:
# A slice
self.source.seek(key.start, os.SEEK_SET)
return self.source.read(key.stop - key.start)
except AttributeError:
# single element
self.source.seek(key, os.SEEK_SET)
return self.source.read(1)
它是只读的,不做任何花哨的事情,但我可以像使用mmap一样:
map2 = Mmap(f)
print map2[0:10]
print map2[10000000000:10000000010]
只是文件大小没有限制。不太难真的。。。
来自IEEE1003.1:
它需要所有的虚拟地址空间,因为这正是
mmap()
所做的。事实上,内存不足并不重要-你不能映射比可用空间更多的地址空间。既然您将结果和访问视为是内存,那么您建议如何准确地访问文件中超过2^32个字节?即使
mmap()
没有失败,您仍然只能在32位地址空间耗尽空间之前读取第一个4GB。当然,您可以在文件上mmap()
一个滑动的32位窗口,但这并不一定会给您带来任何好处,除非您可以优化访问模式,从而限制访问以前窗口的次数。很抱歉回答了我自己的问题,但我认为真正的问题是我没有意识到mmap是一个具有特定特征和限制的标准POSIX系统调用,Python mmap应该只是公开其功能。
Python文档没有提到POSIX mmap,因此如果您作为一个Python程序员在没有太多POSIX知识的情况下使用它(正如我所做的那样),那么地址空间问题看起来相当随意,而且设计得很糟糕!
感谢其他海报教我mmap的真谛。不幸的是,没有人提出一个更好的方法来代替我手工创建的类,将大文件作为字符串处理,所以我现在必须坚持使用它。也许我会清理它,并使它成为我的模块的公共接口的一部分,当我有机会。
32位程序和操作系统最多只能寻址32位内存,即4GB。还有其他一些因素使总数变得更小;例如,Windows保留了0.5到2GB的硬件访问空间,当然你的程序也会占用一些空间。
编辑:您明显缺少的是对任何操作系统上的mmap机制的理解。它允许您将文件的一部分映射到一个内存范围-完成此操作后,对该部分文件的任何访问都将以尽可能少的开销进行。它的开销很低,因为映射只完成一次,而且不必每次访问不同的范围时都更改。缺点是,您需要一个开放的地址范围,足以满足您要映射的部分。如果一次映射整个文件,则需要在内存映射中有一个足够大的洞来容纳整个文件。如果这样的漏洞不存在,或者比你的整个地址空间还大,它就会失败。
相关问题 更多 >
编程相关推荐