2014-09-03 51 views
2

我有一個用Cython類像下面的有點人爲例如:爲什麼在C編寫這個緩慢的C數組?

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.reject()(和之間的一些其他的事情要真正改變X的值)

我知道我可以使用cpdef來避免額外的包裝調用(__reject()和reject()),但是我的測試表明這沒有區別。

我的問題是:

當我註釋掉self.SX[k] -= dx代碼似乎由10有關的因素是這有望加快?

我明白,訪問內存有成本,但我沒想到代碼會減慢那麼多。

更新

如下建議,改變線

cdef double x 
cdef double dx 

cdef float x 
cdef float dx 

刪除某些鑄造操作的需要,並通過一個因素加快碼約2.

+0

發佈Cython生成的C代碼(的相關部分)會很有用。 – BluePeppers 2014-09-03 12:01:21

+3

雖然它可能只是緩存;沒有這一行,雙循環中唯一使用的內存區域是self.X,所以它很可能一直保留在緩存中。當你添加self.SX行時,堆的數量會增加兩倍,這可能會將它從緩存中推出?取決於nmax的值是什麼 – BluePeppers 2014-09-03 12:03:37

+0

我稍後會試着做。問題是我的實際代碼更加複雜,因此剝離它有點困難。我目前的理論還認爲它是緩存,@BluePeppers。感謝您的輸入。 – inconvergent 2014-09-03 12:04:32

回答

2

我發現可以解釋緩慢,請注意您創建xdxdouble接收float值,通過改變一個問題:

cdef float x 
cdef float dx 

我得到了2倍的加速,因爲它避免了鑄造浮動值在x = self.X[v]之後加倍,然後在self.SX[k] -= dx中再次投射雙倍浮動。

看來你是在你的方法失去緩存,我使用單個陣列通過控制經過2*i+02*i+10self.X1self.SX)的同時訪問self.Xself.SX的值存儲測試時間是一樣的。

+1

好的。我已經接受了這個答案。感謝您的測試! – inconvergent 2014-09-21 08:42:57