Python 内置求和函数 vs. for 循环性能

标签 python performance sum

我注意到 Python 的内置 sum 函数在对 1 000 000 个整数的列表求和时大约比 for 循环快 3 倍:

import timeit

def sum1():
    s = 0
    for i in range(1000000):
        s += i
    return s

def sum2():
    return sum(range(1000000))

print 'For Loop Sum:', timeit.timeit(sum1, number=10)
print 'Built-in Sum:', timeit.timeit(sum2, number=10)

# Prints:
# For Loop Sum: 0.751425027847
# Built-in Sum: 0.266746997833

这是为什么呢? sum是如何实现的?

最佳答案

速度差异实际上大于 3 倍,但是您可以通过首先创建一个包含 100 万个整数的巨大内存列表来降低任一版本的速度。将其与时间试验分开:

>>> import timeit
>>> def sum1(lst):
...     s = 0
...     for i in lst:
...         s += i
...     return s
... 
>>> def sum2(lst):
...     return sum(lst)
... 
>>> values = range(1000000)
>>> timeit.timeit('f(lst)', 'from __main__ import sum1 as f, values as lst', number=100)
3.457869052886963
>>> timeit.timeit('f(lst)', 'from __main__ import sum2 as f, values as lst', number=100)
0.6696369647979736

现在速度差已经上升到5倍以上。

for 循环作为解释的 Python 字节码执行。 sum() 完全在 C 代码中循环。解释字节码和C代码的速度差异很大。

此外,如果 C 代码可以将总和保存在 C 类型中,则它确保不会创建新的 Python 对象;这适用于 intfloat 结果。

反汇编的 Python 版本是这样的:

>>> import dis
>>> def sum1():
...     s = 0
...     for i in range(1000000):
...         s += i
...     return s
... 
>>> dis.dis(sum1)
  2           0 LOAD_CONST               1 (0)
              3 STORE_FAST               0 (s)

  3           6 SETUP_LOOP              30 (to 39)
              9 LOAD_GLOBAL              0 (range)
             12 LOAD_CONST               2 (1000000)
             15 CALL_FUNCTION            1
             18 GET_ITER            
        >>   19 FOR_ITER                16 (to 38)
             22 STORE_FAST               1 (i)

  4          25 LOAD_FAST                0 (s)
             28 LOAD_FAST                1 (i)
             31 INPLACE_ADD         
             32 STORE_FAST               0 (s)
             35 JUMP_ABSOLUTE           19
        >>   38 POP_BLOCK           

  5     >>   39 LOAD_FAST                0 (s)
             42 RETURN_VALUE        

除了解释器循环比 C 慢之外,INPLACE_ADD 将创建一个新的整数对象(超过 255,CPython 将小的 int 对象缓存为单例)。

你可以看到 C implementation在 Python mercurial 代码存储库中,但它在注释中明确指出:

/* Fast addition by keeping temporary sums in C instead of new Python objects.
   Assumes all inputs are the same type.  If the assumption fails, default
   to the more general routine.
*/

关于Python 内置求和函数 vs. for 循环性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24578896/

相关文章:

python - 使用 Python 在 Windows 7 中创建快捷方式文件

python - 将 pandas DataFrame 存储在 PyTables 表中而不存储索引

python - 如何在 Bravado 中设置自定义 http 客户端?

Python效率: is it better to create new variables and assign tasks to it rather than keep on using same variable?

performance - 我如何使 Selenium WebDriver 运行多个小时(CHO)而不会导致崩溃/OutOfMemory 问题?

php - 根据积分总和从MySQL数据库中删除记录

python - 如何累积/收集/求和列表?

python - 从列表中删除包含日期的字符串,而不影响列表中的独立日期

performance - 在 WHERE 中使用条件 =、>=、<= 优化 LOOP AT

Mysql SUM 输出错误