2014-05-08 91 views
3

我有一個非常簡單的函數,我需要加快速度。基本上我有一個16位數字的大陣列,其中有一些漏洞。 (約10%)我需要遍歷數組,找到連續有2個0的區域,然後用上一個和下一個元素的平均值填充它們。這在C中只需要幾毫秒,但是Python正在變得更糟。提高cython數組索引速度

我已經從常規的Python數組切換到numpy數組,然後使用cython編譯我的代碼,但是我仍然離我的目標還很遠。我希望有更多經驗的人可以看看我在做什麼,並給我一些反饋。

我經常Python代碼看起來是這樣的:

self.rawData = numpy.fromfile(ql, numpy.uint16, 50000) 
[snip] 
def fixZeroes(self): 
    for x in range(2,len(self.rawData)): 
     if self.rawData[x] == 0 and self.rawData[x-1] == 0: 
      self.rawData[x] = (self.rawData[x-2] + self.rawData[x+2])/2 
      self.rawData[x-1] = (self.rawData[x-3] + self.rawData[x+1]) /2 

我用Cython代碼看起來非常相似:

import numpy as np 
cimport numpy as np 
DTYPE = np.uint16 
ctypedef np.uint16_t DTYPE_t 

@cython.boundscheck(False) 
def fix_zeroes(np.ndarray[DTYPE_t, ndim=1] raw): 
    assert raw.dtype == DTYPE 
    cdef int len = 50000 

    for x in range(2,len): 
     if raw[x] == 0 and raw[x-1] == 0: 
      raw[x] = (raw[x-2] + raw[x+2])/2 
     raw[x-1] = (raw[x-3] + raw[x+1]) /2 
    return raw 

當我運行這段代碼,性能仍遠慢於我想:

開始用Cython零修復

成品:0:00:36.983681

開始蟒蛇零修復

成品:0:00:41.434476

我真的認爲我必須做一些錯誤的。我見過的大多數文章都談到巨大的性能增加了numpy和cython add,但我幾乎沒有打破10%。

+1

'這隻需要C'幾毫秒。你有C的功能嗎?如果是這樣,只需將它直接包裝到Cython中,然後從Python程序中調用它。 –

+0

@ThaneBrimhall使用Cython與所有boosting指令和類型聲明應該非常接近C –

+0

@ThaneBrimhall - 好點。我有一個C函數,但它是一團糟。我需要重寫算法,這是它的一部分,所以這就是爲什麼它被移植到python。儘管我確實喜歡你的建議。 –

回答

5

你應該聲明x變量您正在使用索引的raw陣列:

cdef int x 

,你也可以使用其他指令,它們通常會提供一個性能提升:

@cython.wraparound(False) 
@cython.cdivision(True) 
@cython.nonecheck(False) 
+2

哇!是的,那是問題所在。我從36.9秒變成了0.0072秒。我會說這是一場勝利。 –

+1

@MaxwellBottiger偉大的,請記住這些指令!將來你可能會面對的另一件事是用'x * x'替換'x ** 2',因爲第一個函數會在函數調用中轉換,例如'pow(x,2)' –