mmap读大文件不一定更快,仅在随机跳读、重复扫描或稀疏访问时有优势;顺序遍历反而常慢于open().read()或for line in file,因其页表开销和缺页延迟更高。

直接用 mmap 读大文件不一定更快,甚至可能更慢——关键看访问模式。随机跳读、重复扫描、或只读取少量分散区域时,mmap 才有明显优势;顺序流式读取反而常被 open().read() 或 for line in file 吊打。
什么时候该用 mmap?看访问是否“稀疏”或“重复”
内存映射不是万能加速器,它把文件逻辑地址映射到进程虚拟内存,靠操作系统按需调页(page fault)。这意味着:
- 首次访问某段数据才触发磁盘 I/O,适合你只读其中几块(比如解析日志里特定时间戳的记录)
- 多次访问同一区域(如反复搜索某个 header)不用重复系统调用,缓存由 OS 管理
- 但如果你从头扫到尾、每字节只读一次,
mmap的页表开销和 TLB 压力反而拖慢速度 - 特别注意:Windows 上
mmap对大文件(>2GB)默认使用MAP_PRIVATE,且不支持ACCESS_READ的细粒度控制,行为和 Linux 不一致
mmap.mmap() 的三个关键参数必须配对设对
常见错误是忽略 length 和 access 的配合关系,导致 ValueError: mmap length is greater than file size 或静默截断:
-
length必须 ≤ 文件大小,设为0表示映射整个文件(Python 3.8+ 支持,旧版需先os.stat().st_size) -
access推荐显式指定:mmap.ACCESS_READ(只读,最安全)、mmap.ACCESS_WRITE(写回文件)、mmap.ACCESS_COPY(写时复制,不落盘) - 不要省略
fileno参数——必须传入已打开的file.fileno(),且文件句柄不能提前关闭,否则映射立即失效 - 示例正确写法:
f = open("big.log", "rb") mm = mmap.mmap(f.fileno(), length=0, access=mmap.ACCESS_READ) # 后续用 mm[1000:2000] 或 mm.find(b"ERROR")
用 find() 和切片代替正则全文扫描
mmap 对象支持字节串方法(find、rfind、split),但不支持 re.findall() 直接作用于 mmap 对象——那会强制拷贝整段到内存。正确做法是:
立即学习“Python免费学习笔记(深入)”;
- 用
mm.find(pattern)定位起始偏移,再用切片提取上下文:mm[pos-100:pos+200] - 避免
mm[:].decode()——这等于把整个文件读进内存,完全失去 mmap 意义 - 如果必须用正则,先用
find缩小范围,再对局部切片调re.search() - 注意编码:mmap 是字节视图,中文需手动
mm[start:end].decode("utf-8"),别指望自动解码
真正容易被忽略的是生命周期管理:mmap 对象不会自动 close,必须显式调用 mm.close(),否则在 Windows 上可能锁住文件,在 Linux 上虽不锁但会占用虚拟内存和文件描述符。尤其在循环处理多个大文件时,漏关会导致 OSError: [Errno 24] Too many open files。


















