小编典典

当整个文件太大时,如何在python中使用mmap

python

我有一个python脚本,它逐行读取文件,并查看每行是否与正则表达式匹配。

我想通过在搜索之前使用内存映射文件来提高该脚本的性能。我研究了mmap示例:http
:
//docs.python.org/2/library/mmap.html

我的问题是,当文件太大(15GB)而无法存储机器内存(4GB)时,如何映射文件?

我这样读取文件:

fi = open(log_file, 'r', buffering=10*1024*1024)

for line in fi: 
    //do somemthong

fi.close()

由于我将缓冲区设置为10MB,因此从性能上来说,它与我映射10MB文件相同吗?

谢谢。


阅读 419

收藏
2021-01-20

共1个答案

小编典典

首先,机器的内存是无关紧要的。相关的是进程的
地址空间

的大小。使用32位Python,该文件大小将低于4GB。使用64位Python,将绰绰有余。

这样做的原因mmap不是要将文件映射到物理内存,而是要映射
虚拟内存

。一个mmapPED文件变得就像为你的程序的特殊的交换文件。考虑这一点可能会有些复杂,但是上面的Wikipedia链接应该会有所帮助。

因此,第一个答案是“使用64位Python”。但显然,这可能不适用于您的情况。

显而易见的替代方法是在前1GB中进行映射,搜索,取消映射,在后1GB中进行映射,依此类推。您可以通过在方法中指定lengthoffset参数来实现此目的mmap。例如:

m = mmap.mmap(f.fileno(), length=1024*1024*1024, offset=1536*1024*1024)

但是,您要搜索的正则表达式可以在前1GB中途找到,而在第二GB中则找到一半。因此,您需要使用窗口化-
在前1GB中映射,搜索,取消映射,然后在部分重叠的1GB中映射,依此类推。

问题是,您需要多少重叠?如果您知道一场比赛的最大可能规模,那么您将不需要什么。而且,如果您不知道……好,那么就没有办法解决您的问题而又不用破坏正则表达式了-
如果这不太明显,请想象一下如何在一个1GB的窗口中找到2GB的匹配项。

回答您的后续问题:

由于我将缓冲区设置为10MB,因此从性能上来说,它与我映射10MB文件相同吗?

与任何性能问题一样,如果它确实很重要,则需要对其进行测试,如果不重要,则不必担心。

如果您想让我猜测:我想mmap这里可能会更快,但这仅仅是因为(正如JF
Sebastian所暗示的那样)re.match频繁循环和调用128K次可能会使您的代码受CPU约束,而不是IO约束。但是您可以无需mmap使用来优化它read。所以,会mmapread?考虑到所涉及的大小,我希望mmap在旧的Unix平台上的性能要快得多,在现代Unix平台上的性能要差不多,而在Windows上的性能要慢一些。(如果使用,您仍然可以mmap通过+readread+获得较大的性能优势,但这在这里并不重要。)但是,实际上,这只是一个猜测。lseek``madvise

使用最引人注目的原因mmap通常是它比read基于代码的代码更简单,而不是更快。当您甚至必须使用窗口时mmap,而当您不需要使用时read,这并不那么引人注目,但是仍然,如果您尝试用两种方式编写代码,我希望您的mmap代码最终会有点更具可读性。(特别是如果您尝试从明显的read解决方案中优化缓冲区副本。)

2021-01-20