TLDR: cython では、なぜ (またはいつ?) numpy 配列を反復する方が python リストを反復するよりも高速ですか?
一般的に: 私は以前に Cython を使用したことがあり、単純な python impl よりも大幅に高速化することができました。
sum() 関数の次の 3 つの実装を検討してください。それらは「cy」と呼ばれるcythonファイルに存在します(明らかに、np.sum()がありますが、それは私の主張の範囲外です..)
素朴なパイソン:
def sum_naive(A):
s = 0
for a in A:
s += a
return s
Pythonリストを期待する関数を持つCython:
def sum_list(A):
cdef unsigned long s = 0
for a in A:
s += a
return s
numpy 配列を期待する関数を持つ Cython。
def sum_np(np.ndarray[np.int64_t, ndim=1] A):
cdef unsigned long s = 0
for a in A:
s += a
return s
実行時間に関しては、sum_np < sum_list < sum_naiveと予想されますが、次のスクリプトは逆を示しています (完全を期すために、 np.sum() を追加しました)。
N = 1000000
v_np = np.array(range(N))
v_list = range(N)
%timeit cy.sum_naive(v_list)
%timeit cy.sum_naive(v_np)
%timeit cy.sum_list(v_list)
%timeit cy.sum_np(v_np)
%timeit v_np.sum()
結果:
In [18]: %timeit cyMatching.sum_naive(v_list)
100 loops, best of 3: 18.7 ms per loop
In [19]: %timeit cyMatching.sum_naive(v_np)
1 loops, best of 3: 389 ms per loop
In [20]: %timeit cyMatching.sum_list(v_list)
10 loops, best of 3: 82.9 ms per loop
In [21]: %timeit cyMatching.sum_np(v_np)
1 loops, best of 3: 1.14 s per loop
In [22]: %timeit v_np.sum()
1000 loops, best of 3: 659 us per loop
どうしたの?cython+numpy が遅いのはなぜですか?
PS
#cython: boundscheck=False
#cython : wraparound=False
を使用します