我刚刚开始学习cython,所以请原谅我的无知。简单地将两个数组一起添加,cython可以改进numpy吗?我非常糟糕地尝试添加两个数组a + b来给出一个新的数组c:
import numpy as np
cimport numpy as np
DTYPE = np.int
ctypedef np.int_t DTYPE_t
def add_arrays(np.ndarray[DTYPE_t, ndim=2] a, np.ndarray[DTYPE_t, ndim=2] b, np.ndarray[DTYPE_t, ndim=2] c):
cdef int x = a.shape[0]
cdef int y = a.shape[1]
cdef int val_a
cdef int val_b
for j in range(x):
for k in range(y):
val_a = a[j][k]
val_b = b[j][k]
c[j][k] = val_a + val_b
return c
然而,当传递这些数组时,这个版本的速度要慢700倍(* edit:而不是numpy):
n = 1000
a = np.ones((n, n), dtype=np.int)
b = np.ones((n, n), dtype=np.int)
c = np.zeros((n, n), dtype=np.int)
我显然错过了很大的东西。
答案 0 :(得分:5)
问题是你正在为c[j][k]
编制二维数组的索引,而实际应该执行c[j,k]
,否则Cython正在使用buf=c[j]
的中间缓冲区,采取buf[k]
,导致减速。您应该使用此正确的索引以及@XavierCombelle指定的cdef
声明。
您可以通过执行以下操作来检查此中间缓冲区是否导致速度变慢:
np.ndarray[DTYPE_t, ndim=1] buf
然后,在循环内部:
buf = c[j]
buf[k] = val_a + val_b
这个声明的缓冲区应该提供与(
)相同的速度(或接近)c[j,k] = val_a + val_b
答案 1 :(得分:3)
我认为你错过了
cdef int j
cdef int k
所以你的变量循环是python对象而不是c
答案 2 :(得分:1)
以下是两个例子:
" numpy方式"
%%timeit
table1 = np.ones((10,10))
table2 = np.ones((10,10))
result = np.zeros((10,10))
table1 + table2
100000 loops, best of 3: 14.5 µs per loop
循环索引方式
%%timeit
def add_arrays(ar1, ar2):
for j in range(len(ar1)):
for k in range(len(ar2)):
val_a = ar1[j][k]
val_b = ar2[j][k]
result[j][k] = val_a + val_b
return result
add_arrays(table1, table2)
1000 loops, best of 3: 307 µs per loop
同样的事情,快了20倍。
有了这一切,我知道我还没有完全回答你的问题,但也许它可以为你的比较提供更好的视角?
对于1000x1000表,[edit],时差更明显;我怀疑是由于建立表格的开销的摊销。
former code: 100 loops, best of 3: 13.1 ms per loop
latter code: 1 loops, best of 3: 2.78 s per loop
这是一个200因素