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

2024-04-25 07:23:10 发布

您现在位置: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,在性能方面,它是否与MMAP10MB文件相同?

谢谢你。


Tags: 文件内存org命令脚本http示例docs
2条回答

我是来尝试使用mmap的,因为我在一个大小为几十GB的文件上使用了fileh.readline(),并希望使它更快。Unix strace实用程序似乎揭示了文件现在是以4kB的块读取的,至少strace的输出在我看来打印得很慢,我知道解析文件需要很多小时。

$ strace -v -f -p 32495
Process 32495 attached
read(5, "blah blah blah foo bar xxxxxxxxx"..., 4096) = 4096
read(5, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096
read(5, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096
read(5, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"..., 4096) = 4096
^CProcess 32495 detached
$

到目前为止,这个线程是唯一解释我不应该试图mmap一个太大的文件的原因。我不明白为什么还没有像mmap_for_dummies(filename)这样的帮助函数,它可以在os.path.size(filename)内部执行,然后执行普通的open(filename, 'r', buffering=10*1024*1024)或执行mmap.mmap(open(filename).fileno())。我当然想避免自己修改滑动窗口方法,但是函数是否做一个简单的决定,是否做mmap对我来说就足够了。

最后要提的是,我仍然不清楚为什么互联网上的一些例子没有解释就提到open(filename, 'rb')(例如https://docs.python.org/2/library/mmap.html)。如果有人经常想在for循环中使用带有.readline()调用的文件,我不知道是应该以'rb'模式打开还是只以'r'模式打开(我想有必要保留'\n')。

感谢您提到buffering=10*1024*1024)参数,这可能比更改代码以获得某种速度更有帮助。

首先,你机器的记忆无关紧要。与此相关的是进程的大小address space。如果是32位的Python,它的容量将低于4GB。有了64位的Python,就足够了。

原因是^{}不是mapping a file进入物理内存,而是virtual memory。一个mmapped文件就像程序的一个特殊交换文件。考虑这个问题可能会有点复杂,但上面的维基百科链接应该会有所帮助。

所以,第一个答案是“使用64位Python”。但很明显,这可能不适用于你的情况。

最明显的替代方法是在第一个1GB中映射、搜索、取消映射、在下一个1GB中映射等等。这样做的方法是将lengthoffset参数指定给mmap方法。例如:

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

但是,您正在搜索的regex可能在前1GB中找到一半,在后1GB中找到一半。因此,您需要在第一个1GB中使用窗口映射,搜索、取消映射,然后在部分重叠的1GB中映射,等等

问题是,你需要多少重叠?如果你知道一个匹配的最大可能大小,你不需要比这更多的东西。如果你不知道…好吧,那么没有办法真正解决这个问题,而不打破你的正则表达式如果这不是显而易见的,想象一下,你怎么可能找到一个2GB匹配在一个1GB的窗口。

回答你的后续问题:

Since I set the buffer to 10MB, in terms of performance, is it the same as I mmap 10MB of file?

对于任何性能问题,如果它真的很重要,您需要测试它,如果它不重要,不要担心它。

如果你想让我猜猜:我认为mmap在这里可能更快,但这仅仅是因为(正如J.F.Sebastian所暗示的那样)循环和调用re.match128K次的频率可能会导致你的代码被CPU绑定而不是IO绑定。但是你可以不用mmap来优化它,只要使用read。那么,mmap会比read快吗?考虑到所涉及的大小,我预计mmap的性能在旧的Unix平台上会快得多,在现代的Unix平台上也差不多,在Windows上会慢得多。(如果您使用的是madvise,您仍然可以从mmap中获得比readread+lseek更大的性能优势,但这与此处无关。)但实际上,这只是一个猜测。

使用mmap最令人信服的原因通常是它比基于read的代码简单,而不是更快。当你不得不使用视窗甚至是mmap时,当你不需要用read进行任何搜索时,这就不那么令人信服了,但是,如果你尝试用两种方式编写代码,我希望你的mmap代码最终会更可读一些。(尤其是当您试图从明显的read解决方案中优化缓冲区副本时。)

相关问题 更多 >