实际上,速度差异超过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对象; 这适用于int
和float
结果。
反汇编的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
对象作为单例缓存)。
你可以在Python 水银代码仓库中查看C实现,但它在评论中明确说明:
sum
函数是在 Python 解释器内部用 C 语言实现的,而你的 for 循环需要被解释执行,所以它运行较慢是正常的。 - Matteo Italiaarr.sum()
更快。 - dwandersonobject
数组,这会大大降低性能。 - Bakuriu