在Python中迭代最快的方法是什么?

5

到目前为止,我从未需要关注这个问题,但现在我需要使用一些需要通过PyOpenGL进行缓冲的大量顶点,并且似乎Python迭代是瓶颈。 这里是情况。 我有一个3D点数组vertices,每一步我都必须为每个顶点计算一个4D颜色数组。 到目前为止,我的方法如下:

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-3FPS。

祝好, 博格丹


如果您使用的是Python 2,请将range替换为xrange - Dan D.
如果迭代真的是瓶颈,一种可能是使用Cython重新编码循环:http://cython.org/ - NPE
2个回答

13
为了提高代码速度,您需要“向量化”它:用NumPy的广播规则替换所有明确的Python循环以使用隐式循环。我可以尝试给出您循环的向量化版本:
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是一个一维数组,应该改为二维数组。


谢谢,从这个建议开始,我实际上成功地使用了numpy来使整个循环只是一些矩阵乘法,这实际上使它运行速度快了大约6倍。 - Bogdan

6
  1. First of all : profile your code with cProfile
  2. You should use xrange instead of range
  3. You should avoid to recall self.color_array 4 times on each loop, try to create a local variable before the loop, and use it into the loop : local_array = self.color_array
  4. try to pre-compute the start_colors[N] and end_colors[N] : start_color_0 = start_colors[0]
  5. try to use list.extend() to reduce lines in loop :

    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
    ])
    

5
请注意,使用cProfile非常简单,只需执行命令python -mcProfile <your_program.py>即可。 - Dan D.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接