首页 文章

添加cython比numpy慢的数组?

提问于
浏览
3

我刚刚开始学习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)

我显然缺少一些非常大的东西 .

3 回答

  • 3

    问题是你正在索引二维数组,如 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

    我想你错过了

    cdef int j
    cdef int k
    

    所以你的变量循环是python对象而不是c

  • 5

    这是两个例子:

    “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表,时差更明显;我怀疑是由于构建表的开销的摊销 .

    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因素

相关问题