python - numpy 的 memmap 写时复制模式是如何工作的?
问题描述
我对 numpymemmap
在使用写时复制 () 时如何处理数据更改感到困惑mmap_mode=c
。由于没有将任何内容写入磁盘上的原始数组,因此我希望它必须将所有更改存储在内存中,因此如果您修改每个元素,可能会耗尽内存。令我惊讶的是,它没有。
我正在尝试减少我在共享集群上运行的机器学习脚本的内存使用量(每个实例占用的内存越少,我可以同时运行的实例越多)。我的数据是非常大的 numpy 数组(每个 > 8 Gb)。我希望使用np.memmap
这些具有小内存(<4Gb 可用)的阵列。
然而,每个实例可能会以不同的方式修改数据(例如,可能每次都选择以不同的方式规范化输入数据)。这对存储空间有影响。如果我使用该r+
模式,那么在我的脚本中规范化数组将永久更改存储的数组。
由于我不想要数据的冗余副本,而只想将原始数据存储在磁盘上,所以我认为我应该使用'c'
模式(写时复制)来打开数组。但是你的改变去哪里了?更改是否仅保存在内存中?如果是这样,如果我更改整个数组,我不会在小内存系统上耗尽内存吗?
这是我预计会失败的测试示例:
在大型内存系统上,创建数组:
import numpy as np
GB = 1000**3
GiB = 1024**3
a = np.zeros((50000, 20000), dtype='float32')
bytes = a.size * a.itemsize
print('{} GB'.format(bytes / GB))
print('{} GiB'.format(bytes / GiB))
np.save('a.npy', a)
# Output:
# 4.0 GB
# 3.725290298461914 GiB
现在,在只有 2 Gb 内存的机器上,这会按预期失败:
a = np.load('a.npy')
但正如预期的那样,这两个会成功:
a = np.load('a.npy', mmap_mode='r+')
a = np.load('a.npy', mmap_mode='c')
问题 1:我运行此代码时内存不足,试图修改 memmapped 数组(无论 r+/c 模式如何都失败):
for i in range(a.shape[0]):
print('row {}'.format(i))
a[i,:] = i*np.arange(a.shape[1])
为什么会失败(特别是为什么即使在r+
可以写入磁盘的模式下也会失败)?我以为memmap
只会将数组的一部分加载到内存中?
问题 2:当我强制 numpy 每隔一段时间刷新一次更改时,两种 r+/c 模式都会成功完成循环。但是c
mode 怎么能做到这一点呢?我不认为flush()
会为模式做任何事情c
?更改不会写入磁盘,因此它们保存在内存中,但不知何故,所有必须超过 3Gb 的更改不会导致内存不足错误?
for i in range(a.shape[0]):
if i % 100 == 0:
print('row {}'.format(i))
a.flush()
a[i,:] = i*np.arange(a.shape[1])
解决方案
Numpy 在这里没有做任何聪明的事情,它只是遵循内置memmap
模块,它有一个access
参数:
接受以下四个值之一:
ACCESS_READ
、、ACCESS_WRITE
或ACCESS_COPY
分别指定只读、直写或写时复制内存。
在 linux 上,这通过调用mmap
系统调用来工作
MAP_PRIVATE
创建私有写时复制映射。映射的更新对映射同一文件的其他进程不可见,并且不会传递到基础文件。
关于你的问题
更改不会写入磁盘,因此它们保存在内存中,但不知何故,所有必须超过 3Gb 的更改不会导致内存不足错误?
更改可能会写入磁盘,但不会写入您打开的文件。它们很可能被分页到某个地方的虚拟内存中。
推荐阅读
- next.js - Applo 客户端单独或 Next js 单独可以在 Next+Applo 应用程序中进行 SSR 吗?
- c# - 有没有办法在套接字接收中引入分隔符?
- jira - jira - JQL 显示问题的所有子项
- python - __init__ 方法 python 中的空列表
- python - 在 python 项目中使用 PyCharm 中现有的 MySQL 连接而无需再次手动连接
- macos - 无法打开“”进行写入——路径上的共享违规。外置硬盘
- python - 使用 pandas 进行数据转换
- python - 将 Raspberry Pi 中的传感器数据生成到 AWS IoT
- javascript - 尝试在节点中删除和创建文件夹
- firebase - 如何在 firebase 函数中实现 Firebase AppCheck 以读取实时数据库?