内存映射随着时间的推移变慢,有替代方法吗?

9
我在磁盘上存储了约700个矩阵,每个矩阵大约有70k行和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, :]

通过逐行计时,我发现随着时间推移,明显是最后一行减速。


更新:绘制负载时间图表得到不同的结果。有一次它看起来像这样,即退化不是逐渐的,而是在确切的400个文件后跳跃。这可能是某种操作系统限制吗?

Plot1

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

Plot2

经过更多测试运行后,似乎第二个图表更符合性能发展的典型情况。


此外,我尝试了循环结束后的 del X,但没有任何影响。访问Python中底层的mmap,即X._mmap.close(),也没有效果。


对于为什么会出现性能不一致的想法?有没有更快的替代方法来存储和检索这些矩阵?


看起来当你转到下一个文件时,底层的mmap文件没有被关闭。这只是一个猜测,但我建议在循环结束时添加del Xnp.memmap的代码是可读的Python代码,但mmap.mmap的代码不是。 - hpaulj
索引的范围是什么,它们是否已排序?即indices_in_Xnp.arange(1000)还是np.random.shuffe(np.arange(0, 70000, 70))很重要。此外,请尝试使计时独立于操作系统文件缓存效果:http://unix.stackexchange.com/q/87908 - user2379410
@morningsun 感谢回复。我尝试对indices_in_Xindices_in_target进行排序,我认为这稍微提高了基线,但是那些看似随机的退化补丁仍然存在。不幸的是,我正在使用共享服务器,并没有sudo权限,因此我无法清除任何缓存。 - fabian789
由于这是一个共享服务器,其他用户是否正在执行导致不一致性能的操作?如果可能存在这种情况,是否有时间可以在没有其他人使用服务器时测试您的代码? - Matt Jordan
这些加载时间包括程序启动吗?还是在你的代码内部进行测试?你是如何控制被测试文件的数量的? - Useless
显示剩余6条评论
2个回答

4
你可以考虑使用。它可以压缩磁盘和内存中的数字数据以加快速度。由于按列而不是行存储数据,因此您可能需要转置矩阵才能获得稀疏读取。请参考bcolz

谢谢!听起来很有前途。使用SSD,我可以获得相当合理的性能,现在我需要与我的主管商量一下是否值得实施bcolz - fabian789

4

HDD在“服务多个主人”方面表现不佳--减速可能比人们预期的要大得多。为了证明这一点,我使用了以下代码来读取我Ubuntu 12.04机器上HDD上的备份文件(每个文件约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)))

运行其中一个“进程”可以给我较好的读取性能。
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上处理大文件时,由于并行读取进程而导致的减速只有两倍,从约440 MB/s降至约220 MB/s。(见我的评论。)


感谢您的输入。我已请求访问一台带有固态硬盘的服务器,看看效果如何。 - fabian789
我刚刚对我的SSD进行了一些大文件的快速测试。一个进程:约440 MB/s;与第二个并行进程:约220 MB/s。因此,在这种情况下,SSD比HDD更擅长“服务两个主人”。 - Ulrich Stern
假设浮点数(4字节)足够,不压缩的情况下,这700个矩阵大约需要59 GB,这使得在一台强大的服务器上实现“全主存储器”解决方案成为可能。而Gary的建议(bcolz)或其他压缩方法可能有助于磁盘或主存储器解决方案。 - Ulrich Stern
再次问候。正如您所预期的那样,SSD使事情变得更快,更一致!因此,我愿意相信“服务> 1个主人”是问题所在。关于“所有主内存”解决方案:我现在实际上有700吉字节可用(!),但我必须在第二步中转换矩阵,使它们具有更高的维度,因此即使有那么多的内存,我也无法同时加载所有矩阵并保留转换后的内容。 - fabian789

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接