Cython:从类型化的memoryview数组中读取值的最快方法是什么?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cython:从类型化的memoryview数组中读取值的最快方法是什么?相关的知识,希望对你有一定的参考价值。

这些年来,我在cython中制定了许多例行程序,并且对性能表现相对满意,直到上周五的一位同事指出我只能获得17倍的提速。我曾以为加速比要大得多。因此,我使用cython -a program.pyx应用查看了生成的代码。 Here is a link to the report。我倾向于在进行非线性数学运算的地方进行循环,例如在while循环中:

cdef double simps(double[:] integrand, double[:] r):
        cdef int n = len(integrand)
        cdef int m = (n-1)/2
        cdef double s = 0.0
        cdef int i = 0
        while (i<m):
            s += (r[2*(i+1)] - r[2*i])*(integrand[2*i] + 4.0*integrand[2*i + 1] + integrand[2*i+2])
            i += 1
        return s/6.

以下行似乎需要很长时间才能评估。

s += (r[2*(i+1)] - r[2*i])*(integrand[2*i] + 4.0*integrand[2*i + 1] + integrand[2*i+2])

原因是所生成的代码对此类型进行了大量检查:

__pyx_t_4 = (2 * (__pyx_v_i + 1));
__pyx_t_5 = -1;
if (__pyx_t_4 < 0) {
  __pyx_t_4 += __pyx_v_r.shape[0];
  if (unlikely(__pyx_t_4 < 0)) __pyx_t_5 = 0;
} else if (unlikely(__pyx_t_4 >= __pyx_v_r.shape[0])) __pyx_t_5 = 0;
if (unlikely(__pyx_t_5 != -1)) {
  __Pyx_RaiseBufferIndexError(__pyx_t_5);
  {__pyx_filename = __pyx_f[0]; __pyx_lineno = 8; __pyx_clineno = __LINE__; goto __pyx_L1_error;}
}

在我看来,它可能正在检查读取的值r[2*i], r[2*i+1]等实际是否未超出数组本身的限制。

您能否提出一种不会引起这些检查的解决方案,并可能解释为什么它会更好地工作?

答案

您可能希望添加here中列出的一些编译器指令,例如boundscheck和wraparound。您可以使用这些特殊的修饰符来注释cython函数,以消除您看到的这些检查。

以上是关于Cython:从类型化的memoryview数组中读取值的最快方法是什么?的主要内容,如果未能解决你的问题,请参考以下文章

在 cython 中快速访问稀疏矩阵:memoryview 与字典向量

cython memoryview 不比 ndarray 快

array.array和memoryview

以类型化 memoryview 作为成员的结构定义

Cython:从参考获得时,Numpy 数组缺少两个第一个元素

将 3D numpy 数组从 cython 传递到 C++