memmap适合处理远超物理内存的大型数组,支持按需加载、切片索引和NumPy运算;需严格匹配文件路径、dtype、shape与mode,首次用'w+'创建,后续用'r+'复用,避免逐行循环和全量操作以防止I/O瓶颈。

memmap 适合什么场景?
当你要读写一个远大于物理内存的矩阵(比如 100GB 的 float64 二维数组),又希望像操作普通 ndarray 一样切片、索引、计算时,memmap 是最直接的方案。它不把整个文件加载进内存,而是通过操作系统虚拟内存机制按需映射页——你访问哪块,OS 才加载哪块。
但它不是万能加速器:随机访问密集、跨页频繁、或需要全量遍历的场景,I/O 会成为瓶颈;且不支持 reshape 后自动调整磁盘布局(shape 改变必须重新创建)。
如何安全创建和复用 memmap 文件?
关键在文件路径、dtype、shape 和 mode 的匹配。一旦创建,后续所有打开都必须严格一致,否则数据错位或报 ValueError: size changed。
-
filename必须是绝对路径或确保工作目录稳定(相对路径易出错) -
dtype和shape决定内存视图结构,改了就得删掉原文件重来 - 首次创建用
mode='w+';之后读写复用统一用mode='r+'(避免意外覆盖) - 建议显式指定
order='C'(默认),避免 Fortran 顺序引发索引混淆
示例:
import numpy as np
# 首次创建:10亿元素的 float32 矩阵(约 4GB)
fp = np.memmap('big_matrix.dat', dtype='float32', mode='w+', shape=(100000, 10000), order='C')
fp[0, :] = np.random.rand(10000).astype('float32') # 写第一行
fp.flush() # 强制写入磁盘,尤其重要
为什么切片慢、.sum() 卡住、甚至段错误?
因为 memmap 对象本身不缓存数据,每次索引都触发系统调用。常见陷阱:
- 用
for i in range(N): arr[i, :]循环逐行访问 → 大量小 I/O,极慢。应改用批量切片,如arr[1000:2000, :] - 直接调
arr.sum()→ 触发全文件扫描,可能耗尽 I/O 带宽并阻塞其他进程。建议分块聚合:np.sum(arr[i:i+10000], axis=0) - 在多进程里共享同一个
memmap实例 → 不安全。每个进程应各自用相同参数新建memmap对象(底层映射同一文件,OS 保证一致性) - 在 Windows 上用
mode='r+'打开只读文件 → 报错。Windows 要求文件实际可写权限,哪怕你只读
和 HDF5、Zarr 比有什么不可替代性?
memmap 最大优势是零依赖、零序列化开销、与 NumPy API 完全透明。但缺点也很硬:只支持单个连续二进制块,不支持压缩、元数据、分块策略或并发写入。
如果你需要:
- 带属性/坐标/压缩的科学数据 → 用
h5py或zarr - 频繁追加行、动态 shape →
memmap不行,得换格式 - 纯数值计算流水线,且已有 .dat/.bin 原始数据 →
memmap是最快接入方式
注意:memmap 不做类型转换——写入 int32 但用 float64 打开,结果就是位模式误读,不会报错,但数值全错。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











