【发布时间】:2010-12-12 07:55:36
【问题描述】:
[编辑:此问题仅适用于 32 位系统。如果您的计算机、操作系统和 python 实现是 64 位的,那么 mmap-ing 大文件可以可靠地工作并且非常高效。]
我正在编写一个模块,其中允许对文件进行按位读取访问。这些文件可能很大(数百 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]
除了对文件大小没有限制。真的不太难……
【问题讨论】:
-
但是没有mmap的功能。 mmap 公开了一个缓冲区接口,您可以对其进行正则表达式匹配。 mmap 支持写入文件,mmap 支持共享内存。你的代码,甚至你的方法,都不会那样做。
-
嗯,它具有 small 数量的 mmap 功能,但不受地址空间限制的影响。这只是一段玩具代码——我并不是说它是一个替代品!我认为这种方法模仿 mmap 的功能没有问题,尽管我可以理解它无法匹配性能。
-
因为它不能实现mmap的功能。您将如何使用此实现 IPC,以便子进程可以通过共享内存块与父进程通信?此外,您的示例不是线程安全的,因为可能会发生不同线程中的两个 getitem 调用,以便第二个的查找在第一个查找之后立即发生,导致第一个的读取给出结果错误。
-
@dalke:好吧,我让步!正如我充分证明的那样,我对 POSIX mmap 了解不多。我只需要我可以相当简单地完成的功能子集(无线程等)。我会相信你的话:)
标签: python performance memory mmap