2011-12-12 111 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 ' –