Python NumPy UFUNC在一个轴上比另一个轴快2倍

Python NumPy UFUNC在一个轴上比另一个轴快2倍,python,performance,numpy,numpy-ufunc,numpy-ndarray,Python,Performance,Numpy,Numpy Ufunc,Numpy Ndarray,我做了一些计算,并测量了UFUNC在不同轴上的性能,以使代码更具性能 In [51]: arr = np.arange(int(1E6)).reshape(int(1E3), -1) In [52]: %timeit arr.cumsum(axis=1) 2.27 ms ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each) In [53]: %timeit arr.cumsum(axis=0) 4.16 ms ± 10

我做了一些计算,并测量了UFUNC在不同轴上的性能,以使代码更具性能

In [51]: arr = np.arange(int(1E6)).reshape(int(1E3), -1)

In [52]: %timeit arr.cumsum(axis=1)
2.27 ms ± 10.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [53]: %timeit arr.cumsum(axis=0)
4.16 ms ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
在轴1上几乎比在轴0上快2倍。为什么会这样?幕后发生了什么?很高兴能清楚地理解背后的原因。谢谢


更新:经过一番研究后,我意识到如果有人在构建一个应用程序时总是只在某个轴上求和,那么应该按照适当的顺序初始化数组:即axis=1和的C顺序或axis=0和的Fortran顺序,以节省CPU时间

另外:这个优秀的答案对我的帮助很大

这些数组是。因此,当你对轴1求和时,
这些数字可以在连续的内存阵列中找到。这允许更好的缓存性能,从而更快地访问内存(参见“”)。我假设这就是你在这里看到的效果。

你有一个正方形数组。看起来是这样的:

1 2 3
4 5 6
7 8 9
1 2 3 4 5 6 7 8 9
1 4 7 2 5 8 3 6 9
但是计算机内存是线性寻址的,所以对于计算机来说,它看起来是这样的:

1 2 3
4 5 6
7 8 9
1 2 3 4 5 6 7 8 9
1 4 7 2 5 8 3 6 9
或者,如果你仔细想想,它可能是这样的:

1 2 3
4 5 6
7 8 9
1 2 3 4 5 6 7 8 9
1 4 7 2 5 8 3 6 9
如果您尝试求和
[1 2 3]
[4 5 6]
(一行),则第一个布局会更快。如果您尝试求和
[1 4 7]
[2 5 8]
,则第二种布局速度更快

这是因为从内存加载数据一次只发生一条“缓存线”,通常为64字节(8个值,NumPy的默认数据类型为8字节浮点)

您可以使用
order
参数控制在构造数组时NumPy使用的布局


有关这方面的更多信息,请参阅:

实际上,性能将取决于内存中阵列的顺序:

In [36]: arr = np.arange(int(1E6)).reshape(int(1E3), -1)

In [37]: arrf = np.asfortranarray(arr) # change order

In [38]: %timeit arr.cumsum(axis=1)
1.99 ms ± 32.6 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [39]: %timeit arr.cumsum(axis=0)
14.6 ms ± 229 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [41]: %timeit arrf.cumsum(axis=0)
1.96 ms ± 19.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

In [42]: %timeit arrf.cumsum(axis=1)
14.6 ms ± 148 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

有关更多详细信息,请参见

我的机器上的对比度更大。我可以想象行求和比缓存更友好。@cᴏʟᴅsᴘᴇᴇᴅ 很可能是这样,因为我在集群上进行了尝试:)。此外,不仅是
sum
几乎所有可以在轴上减少的UFUNC的行为都是相同的