【问题标题】:NumPy memmap performance issuesNumPy memmap 性能问题
【发布时间】:2017-03-17 18:02:22
【问题描述】:

我有一个存储为 NumPy 内存映射的大型 (75000 x 5 x 6000) 3D 数组。如果我像这样简单地迭代第一个维度:

import numpy as np
import time

a = np.memmap(r"S:\bin\Preprocessed\mtb.dat", dtype='float32', mode='r', shape=(75000, 5, 6000))
l = []
start = time.time()
index = np.arange(75000)
np.random.shuffle(index)
for i in np.array(index):
    l.append(np.array(a[i]) * 0.7)
print(time.time() - start)

>>> 0.503

迭代发生得非常快。但是,当我尝试在更大程序的上下文中迭代同一个 memmap 时,对 memmap 的单独调用将花费多达 0.1 秒,而拉取所有 75000 条记录将花费近 10 分钟。

较大的程序太长,无法在这里重现,所以我的问题是:是否有任何已知问题会导致 memmap 访问显着变慢,也许是 Python 内存中保存了大量数据?

在较大的程序中,用法如下所示:

import time
array = np.memmap(self.path, dtype='float32', mode='r', shape=self.shape)
for i, (scenario_id, area) in enumerate(self.scenario_areas):
    address = scenario_matrix.lookup.get(scenario_id)
    if address:
        scenario_output = array[address]
        output_total = scenario_output * float(area)
        cumulative += output_total  # Add results to cumulative total
        contributions[int(scenario_id.split("cdl")[1])] = output_total[:2].sum()
del array

第二个示例需要 10 多分钟才能执行。 scenario_output = array[address] 行的计时,它只是从 memmap 中拉出记录,在 0.0 和 0.5 之间变化 - 半秒 拉出一条记录。

【问题讨论】:

  • 是否需要立即将数据写回数组? r+ 可能会让你慢下来..
  • 我假设您的文件大约是 9GB? (8.4 GiB) 10 分钟,增加处理和写回并不太可怕(除非您使用的是 ssd)
  • 已知问题是,除非所有内容都适合内存,否则您将交换/执行 io。如果您的访问在存储顺序中是非连续的,这可能会非常慢。
  • 你能改变你的测试用例的内部循环来做一些像你的实际程序一样的 * 0.7 吗?此外,您可以将所有这些内容结合起来,让您的问题更具可读性,无需添加手动编辑历史记录,无论如何都会保留一个。
  • 您不会在每次访问时将这些计时数据打印到控制台,是吗?

标签: python numpy numpy-memmap


【解决方案1】:

据我所知,python 中的 memmap 没有任何独立于一般操作系统级别限制的限制。所以我猜你要么有操作系统级别的内存瓶颈(可能是不同大型 mmap 的缓存之间的交互),要么你的问题出在其他地方。

很高兴您已经有一个参考实现来显示操作应该有多快。您需要系统地测试不同的可能原因。以下是一些有助于确定原因的方向。

首先,在参考实现中使用 cProfile,以便更好地了解瓶颈在哪里。您将获得函数调用列表以及每个函数花费的时间。这可能会导致意想不到的结果。一些猜测:

  1. 是否大部分时间都花在了您发布的代码中?如果没有,分析可能会暗示另一个方向。
  2. self.scenario_areas 是类似于列表的还是执行一些隐藏且昂贵计算的迭代器?
  3. 可能是查找scenario_matrix.lookup.get(scenario_id) 很慢。检查一下。
  4. contributions 是一个普通的 python 列表或字典,还是它在幕后的分配上做了什么奇怪的事情?

只有当你确认时间实际上是花在scenario_output = array[address] 行时,我才会开始假设mmap 文件之间的交互。如果是这种情况,请开始注释掉涉及其他内存访问的部分代码并重复分析代码以更好地了解发生了什么。

我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    您可能无法使用 np.memmap 避免性能问题,

    我建议尝试类似https://turi.com/products/create/docs/generated/graphlab.SFrame.html

    SFrame/SArray 让您可以直接从磁盘读取表格数据,这对于大型数据文件通常会更快。

    它是开源的,可在https://github.com/turi-code/SFrame获得

    【讨论】:

      猜你喜欢
      • 2020-10-10
      • 2018-01-15
      • 2012-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-14
      相关资源
      最近更新 更多