理解和功能函数比“for循环”更快?

就Python的性能而言,它是一种列表理解,还是比for循环更快的功能,如map(),filter()和reduce()? 为什么在技术上他们“以C速度运行”,而“for循环以python虚拟机速度运行”?

假设在我正在开发的游戏中,我需要使用for循环绘制复杂而庞大的地图。 这个问题肯定是相关的,因为如果列表理解确实比较快,那么为了避免滞后(尽管代码的视觉复杂性),这将是一个更好的选择。


以下是基于经验的粗略指导和受过教育的猜测。 你应该timeit或配置您的具体用例来获得实实在在的数字,这些数字可能偶尔与下面的同意。

列表理解通常比精确等价for循环(实际构建列表)要快一点点,这很可能是因为它不必在每次迭代中查找列表及其append方法。 但是,列表理解仍然会执行字节码级循环:

>>> dis.dis(<the code object for `[x for x in range(10)]`>)
 1           0 BUILD_LIST               0
             3 LOAD_FAST                0 (.0)
       >>    6 FOR_ITER                12 (to 21)
             9 STORE_FAST               1 (x)
            12 LOAD_FAST                1 (x)
            15 LIST_APPEND              2
            18 JUMP_ABSOLUTE            6
       >>   21 RETURN_VALUE

由于创建和扩展列表的开销,使用列表理解代替不构建列表的循环,无意义地累积无意义值的列表,然后将列表丢弃,往往会更慢。 列表理解本身并不比旧的循环更快。

至于函数列表处理函数:虽然这些函数是用C语言编写的,并且可能优于用Python编写的等效函数,但它们并不一定是最快的选项。 如果函数用C语言编写,则预计会加速一些。 但大多数情况下使用lambda (或其他Python函数),重复设置Python堆栈帧等的开销会节省任何费用。 简单地做同样的工作,没有函数调用(例如列表理解而不是mapfilter )通常稍微快一点。

假设在我正在开发的游戏中,我需要使用for循环绘制复杂而庞大的地图。 这个问题肯定是相关的,因为如果列表理解确实比较快,那么为了避免滞后(尽管代码的视觉复杂性),这将是一个更好的选择。

很有可能,如果这样的代码在编写好的非“优化”Python时速度还不够快,那么没有任何一个Python级别的微型优化能够使它足够快,并且你应该开始考虑下降到C。微型优化通常可以大大加快Python代码的速度,对此有一个较低的(绝对值)限制。 而且,即使在你达到天花板之前,它也变得更具成本效益(15%的加速比300%的加速度,同样的努力)咬住子弹并写出一些C.


如果你检查python.org上的信息,你可以看到这个总结:

Version Time (seconds)
Basic loop 3.47
Eliminate dots 2.45
Local variable & no dots 1.79
Using map function 0.54

但是您应该详细阅读上述文章,以了解性能差异的原因。

我也强烈建议你应该使用timeit来计算你的代码。 在一天结束时,可能会出现这样的情况,例如,您可能需要在满足条件时跳出for循环。 它可能比通过调用map查找结果更快。


你具体询问map(),filter()和reduce(),但是我想你一般都想知道函数式编程。 在测试了一组点之间所有点之间距离的问题之后,函数式编程(使用来自内置itertools模块的starmap函数)结果比for-loops稍慢(以1.25倍的长度, 事实上)。 以下是我使用的示例代码:

import itertools, time, math, random

class Point:
    def __init__(self,x,y):
        self.x, self.y = x, y

point_set = (Point(0, 0), Point(0, 1), Point(0, 2), Point(0, 3))
n_points = 100
pick_val = lambda : 10 * random.random() - 5
large_set = [Point(pick_val(), pick_val()) for _ in range(n_points)]
    # the distance function
f_dist = lambda x0, x1, y0, y1: math.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2)
    # go through each point, get its distance from all remaining points 
f_pos = lambda p1, p2: (p1.x, p2.x, p1.y, p2.y)

extract_dists = lambda x: itertools.starmap(f_dist, 
                          itertools.starmap(f_pos, 
                          itertools.combinations(x, 2)))

print('Distances:', list(extract_dists(point_set)))

t0_f = time.time()
list(extract_dists(large_set))
dt_f = time.time() - t0_f

功能版本比程序版本更快吗?

def extract_dists_procedural(pts):
    n_pts = len(pts)
    l = []    
    for k_p1 in range(n_pts - 1):
        for k_p2 in range(k_p1, n_pts):
            l.append((pts[k_p1].x - pts[k_p2].x) ** 2 +
                     (pts[k_p1].y - pts[k_p2].y) ** 2)
    return l

t0_p = time.time()
list(extract_dists_procedural(large_set)) 
    # using list() on the assumption that
    # it eats up as much time as in the functional version

dt_p = time.time() - t0_p

f_vs_p = dt_p / dt_f
if f_vs_p >= 1.0:
    print('Time benefit of functional progamming:', f_vs_p, 
          'times as fast for', n_points, 'points')
else:
    print('Time penalty of functional programming:', 1 / f_vs_p, 
          'times as slow for', n_points, 'points')
链接地址: http://www.djcxy.com/p/1875.html

上一篇: comprehensions and functional functions faster than "for loops"?

下一篇: PHP parse/syntax errors; and how to solve them?