我在比较numpy数组的就地操作和常规操作。 下面是我所做的(Python版本3.7.3):
a1, a2 = np.random.random((10,10)), np.random.random((10,10))
为了进行比较:
^{2}$因为就地操作避免了为每个循环分配内存。我原以为func1
比func2
慢。在
但我得到的是:
In [10]: %timeit func1(a1, a2)
595 ns ± 14.4 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [11]: %timeit func2(a1, a2)
1.38 µs ± 7.87 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [12]: np.__version__
Out[12]: '1.16.2'
这表明func1
仅为{
我发现这个很有趣,决定自己来计时。但是,我没有检查10x10阵列,而是使用NumPy 1.16.2测试了许多不同的阵列大小:
这清楚地表明,对于较小的阵列大小,常规的加法速度更快,而仅对于中等大的阵列大小,就地操作速度更快。还有一个关于100000个元素的奇怪的隆起,我无法解释(它与我计算机上的页面大小很接近,可能使用了不同的分配方案)。在
分配临时数组预期较慢,因为:
尤其是第一点(分配内存)可能在基准测试中没有考虑(不是使用})。这是因为反复请求相同的内存大小可能是非常优化的。这会使使用额外数组进行加法的速度比实际要快一些。在
%timeit
而不是{这里要提到的另一点是,就地加成可能有一个更高的常数因子。如果要执行就地添加,则必须在执行操作之前进行更多的代码检查,例如重叠输入。这可能会给就地加成一个更高的常数因子。在
作为一个更一般的建议:微观基准可能是有帮助的,但它们并不总是真正准确的。您还应该对调用它的代码进行基准测试,以便对代码的实际性能做出更有教育意义的声明。通常这样的微基准测试会碰到一些高度优化的情况(例如反复分配相同数量的内存并再次释放),当代码实际使用时,这种情况不会发生(如此频繁)。在
下面是我使用我的库^{} 为图形使用的代码:
因为你忽略了向量化运算和小矩阵预取的影响。在
注意,矩阵(10 x 10)的大小很小,因此分配临时存储所需的时间并不是很重要(目前),对于缓存大小较大的处理器,这些小矩阵可能仍然可以完全放入一级缓存中,因此,对这些小矩阵执行矢量化操作等所获得的速度增益,将不仅弥补分配一个临时矩阵所损失的时间,还可以弥补直接添加到所分配内存位置中的速度增益。在
但是当你增加矩阵的大小时,情况就不同了
编辑:这是为了
^{pr2}$k = 10
来证明你在我的机器上观察到的小矩阵也是正确的。在相关问题 更多 >
编程相关推荐