为什么在Cython中写入C数组这么慢?

时间:2014-09-03 11:37:40

标签: python optimization cython

我有一个Cython类,如下面的一些人为例子:

cdef class Differential:

  cdef int *SX
  cdef int *X
  cdef int nmax

  def __init__(self, int nmax):

    self.nmax = nmax ## usually around 10*1000

    return

  def __cinit__(self, int nmax, *arg, **args):

    self.SX = <float *>malloc(nmax*cython.sizeof(float))

    ## assume self.X has some content.
    self.X = <float *>malloc(nmax*cython.sizeof(float)) 

    return

  def __dealloc__(self):

    free(self.SX)
    free(self.X)

    return

  @cython.wraparound(False)
  @cython.boundscheck(False)
  @cython.nonecheck(False)
  @cython.cdivision(True)
  cdef void __reject(self, float step) nogil:

    cdef unsigned int v
    cdef unsigned int k

    cdef double x
    cdef double dx

    float_array_init(self.SX,1000,0.) ## writes 0. to the 100000 first elements

    for v in range(1000):

      x = self.X[v]

      for k in range(v+1,1000):

        dx = x-self.X[k]

        # the following line is the "problem":
        self.SX[k] -= dx

    ## some more code
    # manipulate SX some more. this section has less performance impact because it
    # is not a double for-loop, so i have not included it in the example

    # update X
    for v in range(1000):
      self.X[v] += self.SX[v]

def reject(self, float step):
  self.__reject(step)

代码涉及的范围要大得多,但我试图将其删除到仍能说明代码流量的最小数量。

在我的主脚本中,我只创建一个Differential实例,然后我重复调用Differential.reject()(以及其他一些实际更改X值的内容。)

我知道我可以使用cpdef来避免额外的包装调用(__reject()和reject()),但我的测试表明这没有区别。

我的问题如下:

当我注释掉self.SX[k] -= dx行时,代码似乎加速了大约10倍。这是预期的吗?

我知道访问内存有成本,但我没想到代码会减慢那么多。

更新

如下所示,更改行

cdef double x
cdef double dx

cdef float x
cdef float dx

删除了对某些转换操作的需要,并将代码加速了大约2倍。

1 个答案:

答案 0 :(得分:2)

我发现了一个可以解释缓慢的问题,请注意您创建xdx作为double来接收float值,方法是更改​​为:< / p>

cdef float x
cdef float dx

我获得了2倍的加速,因为它避免了在x = self.X[v]中将浮点值的转换加倍,然后在self.SX[k] -= dx中再次从double转换为float。

您的方法中似乎丢失缓存,我使用单个数组测试通过控制self.Xself.SX的值来存储2*i+02*i+1的值{1}}或0self.X1self.SX为{{1}},时间安排相同。