np.save和np.savez读取慢的主因是未启用压缩与内存映射优化:单数组应配mmap_mode='r',多数组用np.savez_compressed,超大文件需Python 3.8+及NumPy≥1.19。

为什么 np.save 和 np.savez 保存的文件有时反而读得慢?
不是格式问题,而是默认没压缩、没内存映射优化。NPZ 文件本质是 ZIP 归档,如果存了多个大数组但没用 np.savez_compressed,解压开销会拖慢加载;而 NPY 文件虽是纯二进制,但如果数组特别大(比如 >2GB),直接 np.load 会一次性载入内存,容易 OOM 或卡顿。
- 单个数组 → 优先用
np.save+mmap_mode='r'(内存映射读取) - 多个数组 → 用
np.savez_compressed,别用裸np.savez - 超大数组(>4GB)→ 确保用 Python 3.8+ 和 NumPy ≥1.19,否则可能报
OSError: [Errno 22] Invalid argument
np.save 保存后,用 np.load 读取却报错 ValueError: Cannot load file containing pickled data?
这是文件被意外用 pickle 写过,或后缀名不对导致 NumPy 误判格式。NPY 文件必须严格由 np.save 生成,且扩展名只能是 .npy;若用 .npz 后缀却调 np.save,NumPy 仍会写成 NPY 格式,但后续 np.load 遇到 .npz 名会强制走 ZIP 解析路径,从而触发 pickle 安全检查失败。
- 保存时确保后缀匹配:单数组用
.npy,多数组用.npz - 不要手动改文件后缀,也不要混用
pickle.dump和np.save - 验证文件头:
head -c 6 your_file.npy应输出\x93NUMPY(小端字节序)
如何让 np.load 不加载全部数据,只读某一部分?
靠 mmap_mode 参数实现零拷贝访问,尤其适合只查子集、做切片或迭代的场景。它不把整个数组搬进内存,而是通过操作系统内存映射按需读页。
-
np.load('data.npy', mmap_mode='r')返回一个memmap对象,支持索引、切片、.shape等操作 - 不能对
mmap_mode='r'的数组调.copy()或赋值,会报TypeError: Cannot change memory mapping - 如果需要修改,先
arr.copy()转成普通 ndarray,再操作 - 注意:Windows 上对大于 2GB 的文件启用 mmap 可能失败,建议用
mmap_mode='c'(copy-on-write)替代
np.savez_compressed 比 np.savez 快还是慢?
写入更慢,读取更快——这是典型空间换时间。压缩本身耗 CPU,但减少了磁盘 I/O 和解包时的数据搬运量,尤其在 SSD 速度受限或网络存储(如 NFS)场景下收益明显。
立即学习“Python免费学习笔记(深入)”;
- 压缩率取决于数据:全零或重复值多的数组,
np.savez_compressed可达 10x 压缩比;随机浮点数通常只有 1.2–1.5x - 读取时自动解压到内存,无需额外步骤;但无法 mmap,所有数组都会被完整加载
- 若要部分加载,只能先
np.load('file.npz')得到对象,再用键名索引,例如npz['arr_0'],这步仍会解压对应数组
真正影响性能的从来不是后缀名,而是你是否在保存时就决定了访问模式:一次性全量加载,还是按需映射。选错方式,后面再优化 I/O 也补不回设计缺陷。



















