为什么 Python 的内置 sum 比手动求和慢得多?

zvo*_*one 6 python python-3.x

这是我的简单代码示例:

import time

t0 = time.time()
s = 0
for i in range(1000000):
    s += i
t1 = time.time()

print(s, t1 - t0)

t0 = time.time()
s = sum(i for i in range(1000000))
t1 = time.time()

print(s, t1 - t0)
Run Code Online (Sandbox Code Playgroud)

在我的电脑上(使用 Python 3.8)它打印:

499999500000 0.22901296615600586
499999500000 1.6930372714996338
Run Code Online (Sandbox Code Playgroud)

那么,执行+=100 万次比调用快 7 倍sum?这真是出乎意料。它在做什么?


编辑:我愚蠢地允许调试器附加到进程并干扰我的测量,这最终是导致缓慢的原因。随着调试器的退出,测量不再那么不可预测。正如一些答案清楚地表明的那样,我观察到的情况应该不会发生。

AKX*_*AKX 5

让我们使用timeit适当的基准测试并使比较不同的 Python 版本变得容易,让我们在 Docker 容器中运行它:

so62514160.py

N = 1000000

def m1():
    s = 0
    for i in range(N):
        s += i

def m2():
    s = sum(i for i in range(N))

def m3():
    s = sum(range(N))
Run Code Online (Sandbox Code Playgroud)

so62514160bench.sh

for image in python:2.7 python:3.6 python:3.7 python:3.8; do
    for fun in m1 m2 m3; do
        echo -n "$image" "$fun "
        docker run --rm -it -v $(pwd):/app -w /app -e PYTHONDONTWRITEBYTECODE=1 "$image" python -m timeit -s 'import so62514160 as s' "s.$fun()"
    done
done
Run Code Online (Sandbox Code Playgroud)

在我的机器上的结果:

python:2.7 m1 10 loops, best of 3:  43.5 msec per loop
python:2.7 m2 10 loops, best of 3:  39.6 msec per loop
python:2.7 m3 100 loops, best of 3: 17.1 msec per loop
python:3.6 m1 10 loops, best of 3:  41.9 msec per loop
python:3.6 m2 10 loops, best of 3:  46 msec per loop
python:3.6 m3 100 loops, best of 3: 17.7 msec per loop
python:3.7 m1 5 loops, best of 5:   45 msec per loop
python:3.7 m2 5 loops, best of 5:   40.7 msec per loop
python:3.7 m3 20 loops, best of 5:  17.3 msec per loop
python:3.8 m1 5 loops, best of 5:   48.2 msec per loop
python:3.8 m2 5 loops, best of 5:   44.6 msec per loop
python:3.8 m3 10 loops, best of 5:  19.2 msec per loop
Run Code Online (Sandbox Code Playgroud)

阴谋

在此处输入图片说明


zvo*_*one 1

啊,我自己找到了答案,但这又提出了另一个问题。

所以,这要快得多:

t0 = time.time()
s = sum(range(1000000))
t1 = time.time()

print(s, t1 - t0)
Run Code Online (Sandbox Code Playgroud)

结果是:

499999500000 0.05099987983703613
Run Code Online (Sandbox Code Playgroud)

因此,如预期的那样,sum比 更快+=,但生成器表达式(i for i in range(n))比其他表达式慢得多。

不得不说,这也是相当令人惊讶的。

  • 顺便说一句,这不是我们对代码进行基准测试的方式,请查看“timeit”模块 (3认同)