bee*_*eep 13 python performance numpy
我注意到,非常紧张,np.sum比手写总和慢10倍.
带轴的np.sum:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1.sum(axis=1)
%timeit test(p1)
Run Code Online (Sandbox Code Playgroud)
每回路186μs±4.21μs(平均值±标准偏差,7次运行,每次1000次循环)
没有轴的np.sum:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1.sum()
%timeit test(p1)
Run Code Online (Sandbox Code Playgroud)
每回路17.9μs±236 ns(平均值±标准偏差,7次运行,每次10000次循环)
+:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1[:,0] + p1[:,1]
%timeit test(p1)
Run Code Online (Sandbox Code Playgroud)
每个环路15.8μs±328 ns(平均值±标准偏差,7次运行,每次100000次循环)
乘法:
p1 = np.random.rand(10000, 2)
def test(p1):
return p1[:,0]*p1[:,1]
%timeit test(p1)
Run Code Online (Sandbox Code Playgroud)
每个环路15.7μs±701 ns(平均值±标准偏差,7次运行,每次10000次循环)
我没有看到任何理由.知道为什么吗?我的numpy版本是1.15.3.
编辑:10000000:
np.sum (with axis): 202 ms (5 x)
np.sum (without axis): 12 ms
+ : 46 ms (1 x)
* : 44.3 ms
Run Code Online (Sandbox Code Playgroud)
所以我想在某种程度上会有一些开销.
主要区别a.sum(axis=1)在于计算时的开销较大.计算减少量(在这种情况下sum)并不是一件小事:
但是,如果只需要添加两个元素,那么所有这些都不是必需的,并且不比天真的总和更好 - 您可以获得相同的结果,但开销更少,速度更快.
对于仅1000个元素,调用numpy功能的开销可能高于实际执行这1000次添加(或者就此而言的乘法,因为在现代CPU上,流水线加法/乘法具有相同的成本) - 您可以看到,对于10 ^ 4运行时间只有2倍左右,这是开销在10 ^ 3中发挥更大作用的明确信号!在这个答案中,更详细地研究了开销和缓存未命中的影响.
让我们看一下profiler-result,看看上面的理论是否成立(我使用perf):
用于a.sum(axis=1):
17,39% python umath.cpython-36m-x86_64-linux-gnu.so [.] reduce_loop
11,41% python umath.cpython-36m-x86_64-linux-gnu.so [.] pairwise_sum_DOUBLE
9,78% python multiarray.cpython-36m-x86_64-linux-gnu.so [.] npyiter_buffered_reduce_iternext_ite
9,24% python umath.cpython-36m-x86_64-linux-gnu.so [.] DOUBLE_add
4,35% python python3.6 [.] _PyEval_EvalFrameDefault
2,17% python multiarray.cpython-36m-x86_64-linux-gnu.so [.] _aligned_strided_to_contig_size8_src
2,17% python python3.6 [.] lookdict_unicode_nodummy
...
Run Code Online (Sandbox Code Playgroud)
使用的开销reduce_loop,pairwise_sum_DOUBLE是主导.
用于a[:,0]+a[:,1]):
7,24% python python3.6 [.] _PyEval_EvalF
5,26% python python3.6 [.] PyObject_Mall
3,95% python python3.6 [.] visit_decref
3,95% python umath.cpython-36m-x86_64-linux-gnu.so [.] DOUBLE_add
2,63% python python3.6 [.] PyDict_SetDef
2,63% python python3.6 [.] _PyTuple_Mayb
2,63% python python3.6 [.] collect
2,63% python python3.6 [.] fast_function
2,63% python python3.6 [.] visit_reachab
1,97% python python3.6 [.] _PyObject_Gen
Run Code Online (Sandbox Code Playgroud)
正如所料:Python开销起着重要作用,使用简单DOUBLE_add.
呼叫时开销更少 a.sum()
reduce_loop不是每行都要调用,而是只调用一次,这意味着开销要小得多.所以可以预期,这a.sum()是更快的(尽管事实上,2000年而不是1000必须加成 - 但正如我们已经看到它主要是关于开销和实际工作 - 增加不负责的大部分运行时间).
通过运行获取数据:
perf record python run.py
perf report
Run Code Online (Sandbox Code Playgroud)
和
#run.py
import numpy as np
a=np.random.rand(1000,2)
for _ in range(10000):
a.sum(axis=1)
#a[:,0]+a[:,1]
Run Code Online (Sandbox Code Playgroud)