numpy数组的Cython开销

时间:2016-12-08 08:44:59

标签: python performance numpy cython

我在cython中编写了一个简单的插值函数,可以从其他cython代码中调用(很多)。其中一个参数是numpy数组:

@cython.boundscheck(False) 
@cython.cdivision(True)
@cython.wraparound(False) 
cdef double interpU_cython(double kX,double kY,int iX,int iY, int iTheta,int nbX,int nbY,np.ndarray[double, ndim=3] u, double outVal):
    cdef double uPt, u0, u1
    if (iX >= 0 and iY >= 0 and iX < nbX-1 and iY < nbY-1):
        u0 = u[iX,iY,iTheta] + (u[iX+1,iY,iTheta]-u[iX,iY,iTheta]) * kX
        u1 = u[iX,iY+1,iTheta] + (u[iX+1,iY+1,iTheta]-u[iX,iY+1,iTheta]) * kX
        uPt = u0 + (u1-u0) * kY
    else:
        uPt = outVal
    return uPt

我用 cython -a 检查了python调用,看起来函数调用依赖于几个python调用:

+01: cimport cython
 02: cimport numpy as np
+03: import numpy as np
 04: 
 05: @cython.boundscheck(False)
 06: @cython.cdivision(True)
 07: @cython.wraparound(False)
+08: cdef double interpU_cython(double kX,double kY,int iX,int iY, int iTheta,int nbX,int nbY,np.ndarray[double, ndim=3] u, double outVal):
static double __pyx_f_10FSM_cython_interpU_cython(double __pyx_v_kX, double __pyx_v_kY, int __pyx_v_iX, int __pyx_v_iY, int __pyx_v_iTheta, int __pyx_v_nbX, int __pyx_v_nbY, PyArrayObject *__pyx_v_u, double __pyx_v_outVal) {
  double __pyx_v_uPt;
  double __pyx_v_u0;
  double __pyx_v_u1;
  __Pyx_LocalBuf_ND __pyx_pybuffernd_u;
  __Pyx_Buffer __pyx_pybuffer_u;
  double __pyx_r;
  __Pyx_RefNannyDeclarations
  __Pyx_RefNannySetupContext("interpU_cython", 0);
  __pyx_pybuffer_u.pybuffer.buf = NULL;
  __pyx_pybuffer_u.refcount = 0;
  __pyx_pybuffernd_u.data = NULL;
  __pyx_pybuffernd_u.rcbuffer = &__pyx_pybuffer_u;
  {
    __Pyx_BufFmt_StackElem __pyx_stack[1];
    if (unlikely(__Pyx_GetBufferAndValidate(&__pyx_pybuffernd_u.rcbuffer->pybuffer, (PyObject*)__pyx_v_u, &__Pyx_TypeInfo_double, PyBUF_FORMAT| PyBUF_STRIDES, 3, 0, __pyx_stack) == -1)) __PYX_ERR(0, 8, __pyx_L1_error)
  }
  __pyx_pybuffernd_u.diminfo[0].strides = __pyx_pybuffernd_u.rcbuffer->pybuffer.strides[0]; __pyx_pybuffernd_u.diminfo[0].shape = __pyx_pybuffernd_u.rcbuffer->pybuffer.shape[0]; __pyx_pybuffernd_u.diminfo[1].strides = __pyx_pybuffernd_u.rcbuffer->pybuffer.strides[1]; __pyx_pybuffernd_u.diminfo[1].shape = __pyx_pybuffernd_u.rcbuffer->pybuffer.shape[1]; __pyx_pybuffernd_u.diminfo[2].strides = __pyx_pybuffernd_u.rcbuffer->pybuffer.strides[2]; __pyx_pybuffernd_u.diminfo[2].shape = __pyx_pybuffernd_u.rcbuffer->pybuffer.shape[2];
/* … */
  /* function exit code */
  __pyx_L1_error:;
  { PyObject *__pyx_type, *__pyx_value, *__pyx_tb;
    __Pyx_PyThreadState_declare
    __Pyx_PyThreadState_assign
    __Pyx_ErrFetch(&__pyx_type, &__pyx_value, &__pyx_tb);
    __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_u.rcbuffer->pybuffer);
  __Pyx_ErrRestore(__pyx_type, __pyx_value, __pyx_tb);}
  __Pyx_WriteUnraisable("FSM_cython.interpU_cython", __pyx_clineno, __pyx_lineno, __pyx_filename, 0, 0);
  __pyx_r = 0;
  goto __pyx_L2;
  __pyx_L0:;
  __Pyx_SafeReleaseBuffer(&__pyx_pybuffernd_u.rcbuffer->pybuffer);
  __pyx_L2:;
  __Pyx_RefNannyFinishContext();
  return __pyx_r;
}
 09:     cdef double uPt, u0, u1
+10:     if (iX >= 0 and iY >= 0 and iX < nbX-1 and iY < nbY-1):
+11:         u0 = u[iX,iY,iTheta] + (u[iX+1,iY,iTheta]-u[iX,iY,iTheta]) * kX
+12:         u1 = u[iX,iY+1,iTheta] + (u[iX+1,iY+1,iTheta]-u[iX,iY+1,iTheta]) * kX
+13:         uPt = u0 + (u1-u0) * kY
 14:     else:
+15:         uPt = outVal
+16:     return uPt

是否有一种有效的方法来传递和使用没有显着开销的numpy数组,或者我应该只将c数组用于代码的c编译部分中的所有内容?

使用指向numpy数组第一个元素的指针并在参数中添加数组大小以将其用作一维数组是否安全?

由于

1 个答案:

答案 0 :(得分:1)

查看https://jakevdp.github.io/blog/2012/08/08/memoryview-benchmarks/

这篇博客文章比较了在Cython中使用NumPy数组的几种可能性。

简短的回答是,您应该使用声明为double[:,:,:] u而不是np.ndarray[double, ndim=3] u类型的记忆视图。文档:http://docs.cython.org/en/latest/src/userguide/memoryviews.html

编辑:您可以查询记忆库视图的形状