遍历由 npy memmap 文件组成的 Dask 数组会增加 RAM 而不会释放它

Looping through Dask array made of npy memmap files increases RAM without ever freeing it

上下文

我正在尝试将包含 2D 数组的多个 .npy 文件加载到一个大的 2D 数组中,以便稍后按块处理它。
所有这些数据都比我的 RAM 大,所以我正在使用 memmap storage/loading系统在这里:

pattern = os.path.join(FROM_DIR, '*.npy')
paths = sorted(glob.glob(pattern))
arrays = [np.load(path, mmap_mode='r') for path in paths]
array = da.concatenate(arrays, axis=0)

到目前为止没有问题,如果 RAM 使用率非常低。

问题

现在我有了我的大二维数组,我正在遍历它以逐块处理数据:

chunk_size = 100_000
for i in range(0, 1_000_000, chunk_size):
    subset = np.array(array[i:i+100_000])
    # Process data [...]
    del subset

但即使我不加任何处理地执行这段代码,subsets似乎会无限期地加载到 RAM 中。
这就像 Dask 在幕后加载或复制 memmap 数组到真实的 np.arrays。删除变量或调用 gc.collect() 没有解决这个问题。

您打开了 read-only 的文件,因此您的更改可能没有刷新到磁盘。如果不知道 # process data 中的内容,就不可能准确地说出发生了什么,但乍一看,您似乎应该首先使用 mmap_mode='r+'

有关读取模式的说明,请参阅 memmap docs

不过,一般来说,如果您要遍历块并手动操作数组,dask 无法帮助您节省内存。 Dask 通过为您管理计算、在整个阵列上安排操作以适应您的系统限制,使您免于内存瓶颈。因此,理想的做法是放弃 for 循环并根据 dask.array 操作而不是在 numpy 中编写 # process data 块。如果操作需要用 numpy(或其他 non-dask 模块)编写,您可以使用 dask.array.map_blocks 将其映射到整个数组。正如您当前编写的代码一样,dask 除了增加调度程序的开销外没有做任何事情。