2010-10-22 48 views
2

我正在Python中的模型,我試圖加快執行時間。通過分析代碼,我發現在下面的函數中花費了大量的總處理時間。我想知道是否有任何方法來加速它?加快NumPy的循環

功能的目的是提供一種布爾響應,指出是否NumPy的陣列的指定小區由另一小區的陰影(只在x方向上)。它通過逐步向後逐步檢查每個單元格的高度,以使得給定單元格處於陰影中來實現此目的。在shadow_map值由這裏未示出的另一個函數來計算 - 對於這個例子,取shadow_map爲與類似值的數組:

[0] = 0 (not used) 
[1] = 3 
[2] = 7 
[3] = 18 

add_x功能用來確保數組的下標環周圍(使用時鐘面算術),因爲網格具有周期性邊界(任何一邊離開一邊都會重新出現在另一邊)。

def cell_in_shadow(x, y): 
    """Returns True if the specified cell is in shadow, False if not.""" 

    # Get the global variables we need 
    global grid 
    global shadow_map 
    global x_len 

    # Record the original length and move to the left 
    orig_x = x 
    x = add_x(x, -1) 

    while x != orig_x: 
    # Gets the height that's needed from the shadow_map (the array index is the distance using clock-face arithmetic) 
     height_needed = shadow_map[((x - orig_x) % x_len)] 
     if grid[y, x] - grid[y, orig_x] >= height_needed: 
      return True 

    # Go to the cell to the left 
    x = add_x(x, -1) 

def add_x(a, b): 
    """Adds the two numbers using clockface arithmetic with the x_len""" 
    global x_len 

    return (a + b) % x_len 
+0

'cell_in_shadow'中是否有比其他人更重的特殊行?你是否儘可能少地調用'cell_in_shadow'? – nmichaels 2010-10-22 20:29:23

+0

我不知道如何判斷哪條線比其他線更重。你知道如何做到這一點?我已經檢查了我的所有電話,只有在需要時纔會打電話給它。 – robintw 2010-10-22 20:31:23

+0

@robintw:你是否爲'x'和'y'的每個可能的值調用'cell_in_shadow'? – unutbu 2010-10-22 21:47:00

回答

3

我與桑丘同意用Cython將可能是要走的路,但這裏有幾個小速度起坐:某些變量

A.商店grid[y, orig_x]啓動while循環,並使用之前可變。這將節省一大堆查詢電網陣列。

B.因爲你基本上是剛剛開始x_len - 在shadow_map 1,下努力1,你能避免使用模量那麼大。基本上,變動:

while x != orig_x: 
    height_needed = shadow_map[((x - orig_x) % x_len)] 

for i in xrange(x_len-1,0,-1): 
    height_needed = shadow_map[i] 

或先手與擺脫height_needed變量的所有一起:

if grid[y, x] - grid[y, orig_x] >= shadow_map[i]: 

這些都是小的變化,但他們可能一點點幫助。

另外,如果你計劃去的路線用Cython,我會考慮爲整個網格,或者在一個時間至少由一排你的函數做這個過程。這將節省大量的函數調用開銷。但是,根據您使用結果的方式,您可能無法真正做到這一點。

最後,你有沒有嘗試過使用Psyco?它比Cython花費的工作量要少,儘管它可能不會像速度提升那麼大。我一定會先嚐試一下。

2

如果你不限於嚴格的Python,我會建議使用Cython。它可以允許索引的靜態類型和高效的,以c速度直接訪問numpy數組的底層數據緩衝區。

退房在http://wiki.cython.org/tutorials/numpy

在這個例子中,這是做業務非常相似,你在做什麼(增量指標,訪問numpy的數組的單個元素)一個簡短的教程/例如,添加類型信息的與原始指數相比,指數變量將時間縮短一半。通過向numpy數組添加有效索引,通過給它們類型信息將時間縮短至原始大約1%。

大多數Python代碼已經是有效用Cython,所以你可以用你所擁有的,並添加註釋,然後鍵入需要的地方給你一些速度起坐信息。

我懷疑你會得到最有效地添加類型信息的索引xyorig_x和numpy的陣列。

1

以下指南幾種不同的方法進行比較,以在python優化數值代碼:

Scipy PerformancePython

這是有點過時的,但仍然有幫助的。請注意,它指的是pyrex,後者已被分叉以創建Cython項目,如Sancho所述。

我個人更喜歡f2py,因爲我認爲Fortran 90的有很多的numpy的(例如用一個操作將兩個陣列一起)的不錯的功能,但編譯代碼的全面提速。另一方面,如果你不知道fortran,那麼這可能不是要走的路。

我簡要地用Cython試驗,我發現麻煩的是,在默認情況下用Cython生成代碼,它可以處理任意Python類型,但仍然很慢。然後,您必須花時間添加所有必要的cython聲明以使其更加具體和快速,而如果您使用C或fortran,那麼您將傾向於快速獲得快速代碼。再次說明,我對這些語言已經很熟悉了,而如果Python是你唯一知道的語言,那麼Cython可能會更合適。