2011-12-12 74 views
4

我從來沒有關心過這個問題,但現在我需要使用一些需要被PyOpenGL緩衝的大量頂點,而且好像python迭代是瓶頸。這是情況。我有一個3D點陣列vertices,並且在每一步我都必須爲每個頂點計算一個4D的顏色數組。我的做法迄今:在python中迭代的最快方法

upper_border = len(self.vertices)/3 
#Only generate at first step, otherwise use old one and replace values 
if self.color_array is None: 
    self.color_array = numpy.empty(4 * upper_border) 

for i in range(upper_border): 
    #Obtain a color between a start->end color 
    diff_activity = (activity[i] - self.min)/abs_diff 
    clr_idx = i * 4 
    self.color_array[clr_idx] = start_colors[0] + diff_activity * end_colors[0] 
    self.color_array[clr_idx + 1] = start_colors[1] + diff_activity * end_colors[1] 
    self.color_array[clr_idx + 2] = start_colors[2] + diff_activity * end_colors[2] 
    self.color_array[clr_idx + 3] = 1 

現在我不認爲有什麼我可以做,以消除來自循環的每一步操作,但我猜,必須有一個更優化的性能的方法做那個循環。我在說,因爲在JavaScript中,例如,同樣的微積分產生9FPS,而在Python中,我只得到2-3 FPS。

問候, 波格丹

+0

如果您使用python 2,請用'xrange'替換'range'。 –

+0

如果迭代確實是瓶頸,那麼有一種可能性是在Cython中重新編碼循環:http://cython.org/ – NPE

回答

12

爲了快速使這個代碼,你需要 「vectorise」 吧:替換所有明確的Python循環通過隱式循環,使用NumPy的boradcasting規則。我可以試着給你的循環的矢量化版本:

if self.color_array is None: 
    self.color_array = numpy.empty((len(activity), 4)) 
diff_activity = (activity - self.min)/abs_diff 
self.color_array[:, :3] = (start_colors + 
          diff_activity[:, numpy.newaxis] + 
          end_colors) 
self.color_array[:, 3] = 1 

注意,我不得不做的猜測很多,因爲我不知道你所有的變量是什麼代碼是應該做的,所以我不能保證這段代碼運行。我把color_array變成了一個二維數組,因爲這看起來更合適。這可能需要在代碼的其他部分進行更改(或者需要重新拼合數組)。

我假定self.minabs_diff是標量和所有其他名稱引用以下形狀的NumPy的數組:

activity.shape == (len(vertices) // 3,) 
start_colors.shape == (3,) 
end_colors.shape == (3,) 

它還看起來好像vertices是一個一維陣列和應該是一個兩維陣列。

+0

一樣簡單謝謝,從這個建議開始,我實際上設法使用numpy來使整個循環只是一些矩陣乘法,並且實際上使它運行的速度大約快了6倍。 – Bogdan

6
  1. 首先:分析代碼cProfile
  2. 您應該使用xrange代替範圍
  3. 你應該避免召回在每次循環self.color_array 4倍,嘗試在循環之前創建一個局部變量,並將其用於循環中:local_array = self.color_array
  4. 嘗試預先計算start_colors[N]end_colors[N]start_color_0 = start_colors[0]
  5. 嘗試使用list.extend()減少環線:

    local_array.extend([ 
        start_colors_0 + diff_activity * end_colors_0, 
        start_colors_1 + diff_activity * end_colors_1, 
        start_colors_2 + diff_activity * end_colors_2, 
        1 
    ]) 
    
+4

請注意,使用cProfile與執行'python -mcProfile ' –