为什么Python的mmap不能处理大文件?

2024-06-09 17:42:38 发布

您现在位置:Python中文网/ 问答频道 /正文

[编辑:此问题仅适用于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]

只是文件大小没有限制。不太难真的。。。


Tags: 文件key代码文档selfsourceobjectos
3条回答

来自IEEE1003.1:

The mmap() function shall establish a mapping between a process' address space and a file, shared memory object, or [TYM] typed memory object.

它需要所有的虚拟地址空间,因为这正是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机制的理解。它允许您将文件的一部分映射到一个内存范围-完成此操作后,对该部分文件的任何访问都将以尽可能少的开销进行。它的开销很低,因为映射只完成一次,而且不必每次访问不同的范围时都更改。缺点是,您需要一个开放的地址范围,足以满足您要映射的部分。如果一次映射整个文件,则需要在内存映射中有一个足够大的洞来容纳整个文件。如果这样的漏洞不存在,或者比你的整个地址空间还大,它就会失败。

相关问题 更多 >