内存映射会随着时间的推移而变慢,还有其他选择吗?

Memory-Mapping Slows Down Over Time, Alternatives?

我在磁盘上存储了大约 700 个矩阵,每个矩阵大约有 7 万行和 300 列。

我必须相对快速地将这些矩阵的 部分 加载到内存中的另一个矩阵中,每个矩阵大约 1k 行。我发现最快的方法是使用内存映射,最初我可以在大约 0.02 秒内加载 1k 行。但是,性能根本不一致,有时每个矩阵加载最多需要 1 秒!

我的代码大致如下所示:

target = np.zeros((7000, 300))
target.fill(-1)  # allocate memory

for path in os.listdir(folder_with_memmaps):
    X = np.memmap(path, dtype=_DTYPE_MEMMAPS, mode='r', shape=(70000, 300))
    indices_in_target = ... # some magic
    indices_in_X = ... # some magic
    target[indices_in_target, :] = X[indices_in_X, :]

通过逐行计时,我确定它肯定是最后一行随着时间的推移而变慢。


Upadte:绘制加载时间会给出不同的结果。有一次它看起来像这样,即降级不是渐进的,而是恰好在 400 个文件后跳跃。这会是一些 OS 限制吗?

但另一次看起来完全不同:

经过多次测试,第二个情节似乎是相当典型的性能发展。


另外,我在循环后尝试del X,没有任何影响。通过 X._mmap.close() 访问基础 Python mmap 也不起作用。


关于性能不一致的原因有什么想法吗?是否有更快的替代方法来存储和检索这些矩阵?

HDD 在 "serving more than one master" 方面表现不佳——减速的幅度可能比人们预期的要大得多。为了演示,我使用此代码读取 Ubuntu 12.04 机器硬盘上的备份文件(每个大约 50 MB):

import os, random, time

bdir = '/hdd/backup/'
fns = os.listdir(bdir)

while True:
  fn = random.choice(fns)
  if not fn.startswith("duplicity-full."):
    continue
  ts = time.time()
  with open(bdir+fn, 'rb') as f:
    c = f.read()
  print "MB/s: %.1f" %(len(c)/(1000000*(time.time()-ts)))

运行 其中之一 "processes" 给了我不错的读取性能:

MB/s: 148.6
MB/s: 169.1
MB/s: 184.1
MB/s: 188.1
MB/s: 185.3
MB/s: 146.2

并行添加第二个这样的进程会使速度降低一个数量级以上:

MB/s: 14.3
MB/s: 11.6
MB/s: 12.7
MB/s: 8.7
MB/s: 8.2
MB/s: 15.9

我猜这是(即使用其他硬盘驱动器)导致性能不一致的原因。我的直觉是 SSD 会做得更好。对于我的机器,对于 SSD 上的大文件,并行 reader 进程导致的减速只有两倍,从大约 440 MB/s 到大约 220 MB/s。 (见我的评论。)

您可以考虑使用 bcolz。它压缩磁盘和内存中的数字数据以加快处理速度。您可能必须转置矩阵以获得稀疏读取,因为 bcolz 按列而不是按行存储内容。