我有一个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文件相同吗?
谢谢。
首先,机器的内存是无关紧要的。相关的是进程的 地址空间 的大小。使用32位Python,该文件大小将低于4GB。使用64位Python,将绰绰有余。
这样做的原因mmap不是要将文件映射到物理内存,而是要映射到 虚拟内存 。一个mmapPED文件变得就像为你的程序的特殊的交换文件。考虑这一点可能会有些复杂,但是上面的Wikipedia链接应该会有所帮助。
mmap
因此,第一个答案是“使用64位Python”。但显然,这可能不适用于您的情况。
显而易见的替代方法是在前1GB中进行映射,搜索,取消映射,在后1GB中进行映射,依此类推。您可以通过在方法中指定length和offset参数来实现此目的mmap。例如:
length
offset
m = mmap.mmap(f.fileno(), length=1024*1024*1024, offset=1536*1024*1024)
但是,您要搜索的正则表达式可以在前1GB中途找到,而在第二GB中则找到一半。因此,您需要使用窗口化- 在前1GB中映射,搜索,取消映射,然后在部分重叠的1GB中映射,依此类推。
问题是,您需要多少重叠?如果您知道一场比赛的最大可能规模,那么您将不需要什么。而且,如果您不知道……好,那么就没有办法解决您的问题而又不用破坏正则表达式了- 如果这不太明显,请想象一下如何在一个1GB的窗口中找到2GB的匹配项。
回答您的后续问题:
与任何性能问题一样,如果它确实很重要,则需要对其进行测试,如果不重要,则不必担心。
如果您想让我猜测:我想mmap这里可能会更快,但这仅仅是因为(正如JF Sebastian所暗示的那样)re.match频繁循环和调用128K次可能会使您的代码受CPU约束,而不是IO约束。但是您可以无需mmap使用来优化它read。所以,会mmap比read?考虑到所涉及的大小,我希望mmap在旧的Unix平台上的性能要快得多,在现代Unix平台上的性能要差不多,而在Windows上的性能要慢一些。(如果使用,您仍然可以mmap通过+read或read+获得较大的性能优势,但这在这里并不重要。)但是,实际上,这只是一个猜测。lseek``madvise
re.match
read
lseek``madvise
使用最引人注目的原因mmap通常是它比read基于代码的代码更简单,而不是更快。当您甚至必须使用窗口时mmap,而当您不需要使用时read,这并不那么引人注目,但是仍然,如果您尝试用两种方式编写代码,我希望您的mmap代码最终会有点更具可读性。(特别是如果您尝试从明显的read解决方案中优化缓冲区副本。)