Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
为什么';t Python';mmap如何处理大文件?_Python_Performance_Memory_Mmap - Fatal编程技术网

为什么';t Python';mmap如何处理大文件?

为什么';t Python';mmap如何处理大文件?,python,performance,memory,mmap,Python,Performance,Memory,Mmap,[编辑:此问题仅适用于32位系统。如果您的计算机、操作系统和python实现是64位的,则映射大型文件工作可靠且效率极高。] 我正在编写一个模块,其中包括允许对文件进行按位读取访问的模块。这些文件可能很大(数百GB),因此我编写了一个简单的类,可以将文件当作字符串处理,并隐藏所有查找和读取操作 在我编写包装器类的时候,我并不知道。在阅读mmap的文档时,我想“太好了——这正是我所需要的,我将取出我的代码并用mmap替换它。它可能更高效,删除代码总是好的。” 问题是mmap不适用于大文件!这让我非

[编辑:此问题仅适用于32位系统。如果您的计算机、操作系统和python实现是64位的,则映射大型文件工作可靠且效率极高。]

我正在编写一个模块,其中包括允许对文件进行按位读取访问的模块。这些文件可能很大(数百GB),因此我编写了一个简单的类,可以将文件当作字符串处理,并隐藏所有查找和读取操作

在我编写包装器类的时候,我并不知道。在阅读mmap的文档时,我想“太好了——这正是我所需要的,我将取出我的代码并用mmap替换它。它可能更高效,删除代码总是好的。”

问题是mmap不适用于大文件!这让我非常惊讶,因为我认为这可能是最明显的应用。如果文件超过了几GB,则会出现
环境错误:[Errno 12]无法分配内存。这只发生在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]

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

您将length参数设置为零,这意味着整个文件中的映射。在32位构建中,如果文件长度超过2GB(可能是4GB),则无法实现此功能。

32位程序和操作系统最多只能寻址32位内存,即4GB。还有其他因素使总数更小;例如,Windows为硬件访问预留了0.5到2GB的空间,当然您的程序也会占用一些空间

编辑:您明显缺少的是对任何操作系统上mmap机制的理解。它允许您将文件的一部分映射到一个内存范围——一旦您这样做了,对该部分文件的任何访问都会以尽可能少的开销进行。它的开销很低,因为映射只完成一次,并且不必每次访问不同的范围时都进行更改。缺点是,您需要一个开放的地址范围,该范围足以容纳您试图映射的部分。如果要同时映射整个文件,则需要在内存映射中有一个足够大的孔来容纳整个文件。如果这样一个洞不存在,或者大于您的整个地址空间,它就会失败。

来自IEEE 1003.1:

函数的作用是建立一个 进程地址之间的映射 空间和文件,共享内存 对象,或[TYM]类型内存 反对

它需要所有的虚拟地址空间,因为这正是
mmap()
所做的


它没有真正耗尽内存这一事实并不重要——您无法映射比可用地址空间更多的地址空间。既然您将结果和访问视为内存,那么您打算如何访问文件中超过2^32字节的内容呢?即使
mmap()
没有失败,在32位地址空间的空间用完之前,您仍然只能读取第一个4GB。当然,您可以在文件上滑动32位窗口,但这并不一定会给您带来任何好处,除非您可以优化访问模式,从而限制访问以前的窗口的次数。

您缺少的一点是,mmap是一种内存映射功能,它可以将文件映射到内存中,以便通过任何方式在请求的数据范围内进行任意访问

您正在寻找的内容听起来更像某种数据窗口类,它提供了一个api,允许您随时查看大型数据结构的小窗口。除非调用数据窗口自己的api,否则无法访问此窗口边界以外的内容


这很好,但它不是内存映射,它以更严格的api为代价提供了更宽数据范围的优势。

您要求操作系统在内存范围内映射整个文件。在您通过读/写触发页面错误之前,它不会被读取,但它仍然需要确保整个范围对您的进程可用,如果该范围太大,则会有困难。

mmap模块提供了在大文件中查找所需的所有工具,但由于其他人提到的限制,您不能一次将其全部映射到。您可以一次映射一个大小合适的块,进行一些处理,然后取消映射并映射另一个块。
mmap
类的关键参数是
length
offset
,它们的作用与它们的发音完全相同,允许您映射
length
字节,从映射文件中的byte
offset
开始。每当您希望读取映射窗口之外的内存部分时,都必须在新窗口中进行映射。

很抱歉回答我自己的问题,但我认为我遇到的真正问题是没有意识到mmap是一个标准的POSIX系统调用,具有特定的特性和限制,而Python mmap应该只是公开其功能

Python文档中没有提到POSIX mmap,因此,如果您是作为一名Python程序员而对POSIX没有太多了解(正如我所做的),那么地址空间问题看起来相当随意,设计得很糟糕

多亏了t