numpy内存映射上随机切片的效率

时间:2018-04-22 08:01:39

标签: python numpy numpy-memmap

我有一个20GB,100k x 100k的“float16”2D数组作为数据文件。我按如下方式将其加载到内存中:

fp_read = np.memmap(filename, dtype='float16', mode='r', shape=(100000, 100000))

然后我尝试从中读取切片。我需要采取的垂直切片是有效随机的,但性能非常差,或者我做错了什么?

分析:

我已经与其他形式的横截面切片进行了比较,虽然我不知道它应该是什么,但它要好得多:

%timeit fp_read[:,17000:17005]    # slice 5 consecutive cols
1.64 µs ± 16.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit fp_read[:,11000:11050:10]
1.67 µs ± 21 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit fp_read[:,5000:6000:200]
1.66 µs ± 27.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit fp_read[:,0:100000:20000]    # slice 5 disperse cols
1.69 µs ± 14.7 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

%timeit fp_read[:,[1,1001,27009,81008,99100]]     # slice 5 rand cols
32.4 ms ± 10.9 ms per loop (mean ± std. dev. of 7 runs, 100 loops each)

a = np.arange(100000); b = np.array([1,1001,27009,81008,99100])
%timeit fp_read[np.ix_(a,b)]
18 ms ± 142 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

即使这些timeit函数也无法准确捕获性能下降,因为:

import time
a = np.arange(100000)
cols = np.arange(100000)
np.random.shuffle(cols)
cols = np.sort(cols[:5])
t = time.time()
arr = fp_read[np.ix_(a,cols)]
print('Actually took: {} seconds'.format(time.time() - t))
Actually took: 24.5 seconds

与:

相比
t = time.time()
arr = fp_read[:,0:100000:20000]
print('Actually took: {} seconds'.format(time.time() - t))
Actually took 0.00024 seconds

1 个答案:

答案 0 :(得分:1)

性能差异可通过“基本切片和索引”与“高级索引”see these docs中的一个关键差异来解释。这里的关键是

  

高级索引始终返回数据的副本(与返回view的基本切片形成对比)。

通过将fp_read[:,5000:6000:200]fp_read[:,5000:6000:200].copy()进行比较,可以看出复制伤害的程度。

虽然制作数组副本总是比制作新视图慢,但对于memmap来说尤其糟糕:

  1. 从磁盘读取速度相对较慢。需要从磁盘读取数据以进行(内存中)复制,而视图根本不需要读取任何数据!只有一个新的ndarray对象用内存缓冲区的新偏移量和步长(strides)参数创建。
  2. 数据的内存布局是行主要顺序(与专栏相比,请参阅wikipedia)。对于访问随机列,这意味着必须从磁盘读取每个单个数据值的扇区。将其与连续访问进行比较,其中您只读取每256个值的一个扇区(假设float16和512字节扇区)。对于内存映射io,这种影响甚至更糟,因为数据以4kB的块(内存页)读取,因此8 x 512字节扇区。
  3. 现在我们也可以理解为什么timeit结果不具有代表性:文件的特定部分由操作系统在内存中缓存。