我在python 3.4(64位Windows)中对一个大的(30-ish GB)mmap
ped文件运行正则表达式搜索时遇到“问题”。
基本上,我所观察到的是之间的匹配命中,内存占用量大致上升到匹配之间的字节数。它实际上并没有崩溃,但足迹足以减缓其他进程的速度(因为mmapped文件的大小)。
我的正则表达式来自一个字节字符串,它非常具体,所有量词都有界限。在我的表达式中没有*
或+
,因此不是一个可怕的超越正则表达式的情况(最坏的情况是匹配将是2200字节长,大多数命中较小)。我将匹配的字符串存储在一个列表中,但最多通常只有几千次点击,因此不会占用占用所有空间的点击数。
我现在假设的是正则表达式引擎(sre对吗?)保留内存中匹配项之间的所有字符串,对于小数据集来说很好,但对我来说它并不是真的。所以我的问题是:这个假设是否正确,如果是这样,我可以改变这种行为(最好不要重新编译库!)
代码基本上是这样的:
pattern = re.compile(b"PATTERN.{1,20}", re.DOTALL)
f = open("file.bin", "rb")
mem = mmap.map(f.fileno(), 0, access=mmap.ACCESS_READ)
results = []
for match in pattern.finditer(mem):
results.append(match.group(0))
f.close()
答案 0 :(得分:0)
我不确定是否有办法解决这个问题。您正在以磁盘可以提供的速度快速读取大量数据。除非你有大量的RAM。如果你不在某些时候,你将耗尽RAM必须释放一些。大多数操作系统将使用LRU(最近最少使用)算法来决定从RAM中踢出什么。由于您尽可能快地访问数据,因此内存映射文件使用的大部分内存将具有最近的访问时间。因此意味着他们是“差”候选人被踢出RAM(至少根据操作系统)。
基本上,操作系统在可用内存不足时会对RAM的内容做出糟糕的选择。
但是,您更了解可以释放的内存。因此,您可以以块的形式扫描文件。当您不再需要文件的早期部分时,这将明确地允许操作系统,并允许释放该内存。当然,这会在块的边界产生问题。
作为改善程序内存性能的示例:
import re
import mmap
import os
filename = "some_file.txt"
file_size = os.stat(filename).st_size
chunk_size = 2**32
# chunk_size = 50 # smaller chunk_size I used for testing
regex = re.compile(rb"PATTERN\d{1,20}\n")
max_length = len("PATTERN") + 20 + len("\n")
matches = []
f = open(filename, "rb")
for i in range(0, file_size, chunk_size - max_length + 1):
# compute length of data to search over
length = chunk_size if i + chunk_size <= file_size else file_size - i
m = mmap.mmap(f.fileno(), length=length, offset=i, access=mmap.ACCESS_READ)
# f.seek(i) # used for testing
# m = f.read(length)
for match in regex.finditer(m):
if not (match.end() == len(m) and len(match.group()) < max_length and length == chunk_size):
# if match ends at end of string
# and not maximum length of regex
# but not also at the end of the file
# THEN there *may* be a cross chunk-boundary match
# THUS, defer match to next loop iteration
matches.append(match.group())
m.close()
f.close()