Cython numpy数组索引

Jam*_*mes 4 python arrays indexing numpy cython

我正在尝试使用cython加快一些python代码的速度,并且我在使用cython的-a选项来查看可以在哪些方面进行改进。我的理解是,在生成的html文件中,突出显示的行是调用python函数的行-正确吗?

在下面的琐碎函数中,我arr使用缓冲区语法声明了numpy数组参数。我认为这允许索引操作仅在C语言中进行而不必调用python函数。但是,cython -a(版本0.15)突出显示了我设置的元素值的行arr,尽管不是我读取其元素之一的行。为什么会这样?有没有更有效的方式访问numpy数组元素?

import numpy
cimport numpy

def foo(numpy.ndarray[double, ndim=1] arr not None):
    cdef int i
    cdef double elem
    for i in xrange(10):
      elem = arr[i]          #not highlighted
      arr[i] = 1.0 + elem    #highlighted
Run Code Online (Sandbox Code Playgroud)

编辑:此外,mode缓冲区参数如何与numpy交互?假设我没有改变order的参数numpy.array从默认,是它总是安全使用mode='c'?这实际上会对性能产生影响吗?

在delnan的评论之后进行EDIT:arr[i] += 1也被突出显示(这就是为什么我首先将其拆分,以查看导致问题的操作的哪一部分)。如果我关闭边界检查以简化操作(这与突出显示的内容没有区别),则生成的c代码为:

  /* "ct.pyx":11
 *   cdef int i
 *   cdef double elem
 *   for i in xrange(10):             # <<<<<<<<<<<<<<
 *     elem = arr[i]
 *     arr[i] = 1.0 + elem
 */
  for (__pyx_t_1 = 0; __pyx_t_1 < 10; __pyx_t_1+=1) {
    __pyx_v_i = __pyx_t_1;

    /* "ct.pyx":12
 *   cdef double elem
 *   for i in xrange(10):
 *     elem = arr[i]             # <<<<<<<<<<<<<<
 *     arr[i] = 1.0 + elem
 */
    __pyx_t_2 = __pyx_v_i;
    __pyx_v_elem = (*__Pyx_BufPtrStrided1d(double *, __pyx_bstruct_arr.buf, __pyx_t_2, __pyx_bstride_0_arr));

    /* "ct.pyx":13
 *   for i in xrange(10):
 *     elem = arr[i]
 *     arr[i] = 1.0 + elem             # <<<<<<<<<<<<<<
 */
    __pyx_t_3 = __pyx_v_i;
    *__Pyx_BufPtrStrided1d(double *, __pyx_bstruct_arr.buf, __pyx_t_3, __pyx_bstride_0_arr) = (1.0 + __pyx_v_elem);
  }
Run Code Online (Sandbox Code Playgroud)

fab*_*ioM 5

答案是荧光笔欺骗了读者。我编译了您的代码,高亮显示的指令是处理错误情况和返回值所需的指令,它们与数组分配无关。

确实,如果将代码更改为:

def foo(numpy.ndarray[double, ndim=1] arr not None):
    cdef int i
    cdef double elem
    for i in xrange(10):
      elem = arr[i]
      arr[i] = 1.0 + elem
    return # + add this
Run Code Online (Sandbox Code Playgroud)

高亮显示在最后一行,而不是作业中的更多内容。

您可以使用@ cython.boundscheck进一步加快代码的速度:

import numpy
cimport numpy
cimport cython

@cython.boundscheck(False)
def foo(numpy.ndarray[double, ndim=1] arr not None):
    cdef int i
    cdef double elem
    for i in xrange(10):
      elem = arr[i]
      arr[i] = 1.0 + elem
    return 
Run Code Online (Sandbox Code Playgroud)