【问题标题】:Performance of zeros function in NumpyNumpy 中 zeros 函数的性能
【发布时间】:2017-06-11 19:17:55
【问题描述】:

我刚刚注意到numpyzeros 函数有一个奇怪的行为:

%timeit np.zeros((1000, 1000))
1.06 ms ± 29.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit np.zeros((5000, 5000))
4 µs ± 66 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

另一方面,ones 似乎具有正常行为。 有谁知道为什么用zeros 函数初始化一个小的 numpy 数组比一个大数组需要更多的时间?

(Python 3.5,numpy 1.11)

【问题讨论】:

  • 那么第二个矩阵大了 25 倍,但创建时间只需要 4 倍?这令人惊讶。
  • @JamesKPolk 再读一遍,第二个较大的数组需要 4 微秒,第一个较小的数组需要 1 毫秒!我得到了类似的结果,但结果不那么极端。
  • 我认为这可能是calloc 达到了一个阈值,它从操作系统请求归零内存并且不需要实际初始化它。
  • 当一维数组的大小 S 从 4,150,000 变为 4,200,000 时,使用 np.zeros(S) 将其归零的时间从每循环 5.5 ms 变为每循环 9.6 µs。但是,%timeit 中的循环数同时从 100 变为 100,000。我的猜测是,对于一定大小及以上的数组,最慢和最快运行之间的差异变得足够大,足以触发 1000 倍以上的循环,这大大提高了测量精度并减少了报告的运行时间。不是因为它更短,而是因为它的测量更准确。
  • @DYZ 我正在使用timeit.timeit 函数,控制1000 的数字,我得到0.343710215005558 代表(1000,1000)和0.0028691469924524426 代表(5000, 5000)

标签: python numpy


【解决方案1】:

这看起来像calloc 达到了一个阈值,它向操作系统请求归零内存并且不需要手动初始化它。翻看源码,numpy.zeros最终delegates to calloc获取了一个归零的内存块,如果对比numpy.empty,它不执行初始化:

In [15]: %timeit np.zeros((5000, 5000))
The slowest run took 12.65 times longer than the fastest. This could mean that a
n intermediate result is being cached.
100000 loops, best of 3: 10 µs per loop

In [16]: %timeit np.empty((5000, 5000))
The slowest run took 5.05 times longer than the fastest. This could mean that an
 intermediate result is being cached.
100000 loops, best of 3: 10.3 µs per loop

您可以看到np.zeros 对 5000x5000 数组没有初始化开销。

实际上,在您尝试访问之前,操作系统甚至不会“真正”分配该内存。对 TB 数组的请求在没有 TB 可用空间的机器上成功:

In [23]: x = np.zeros(2**40)  # No MemoryError!

【讨论】:

  • 在 NumPy 1.21.1 中,最后一个命令的结果是 numpy.core._exceptions.MemoryError: Unable to allocate 8.00 TiB for an array with shape (1099511627776,) and data type float64
  • @A.Donda:这可能取决于操作系统。 (不过,我很惊讶 NumPy 有自己的 MemoryError 类。)
猜你喜欢
  • 1970-01-01
  • 2020-09-01
  • 2014-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-11
  • 1970-01-01
相关资源
最近更新 更多