我创建了两个重复两个不同值的长列表。在第一个列表中,值交替出现,在第二个列表中,一个值出现在另一个值之前:
a1 = [object(), object()] * 10**6
a2 = a1[::2] + a1[1::2]
然后我迭代它们,不对它们执行任何操作:
for _ in a1: pass
for _ in a2: pass
两者中哪一个的迭代速度更快?取决于我如何衡量!我用每种计时方法进行了 50 场比赛:
timing method: timeit.timeit
list a1 won 50 times
list a2 won 0 times
timing method: timeit.default_timer
list a1 won 0 times
list a2 won 50 times
为什么两种计时方法给出的结果完全相反?为什么两个列表之间存在速度差异?我预计会是 25-25 两次,而不是 50-0 和 0-50。
之前类似问题的原因以及为什么我认为他们在这里不负责任:
-
分支预测 https://stackoverflow.com/q/11227809/16759116:我没有任何可以产生影响的分支。
-
缓存未命中 https://stackoverflow.com/q/69950010/16759116:不应该发生,因为我只有两个值(而且我什至没有对它们做任何事情)。
-
垃圾收集 https://stackoverflow.com/q/63757763/16759116: 这里不涉及。
- 这些都不能解释opposite无论如何,计时方法之间的速度差异。
我使用的是 Python 3.10,在性能较弱的 Windows 笔记本电脑和功能强大的 Linux Google Compute Engine 实例上得到相同的结果。
完整代码:
from timeit import timeit, default_timer
a1 = [object(), object()] * 10**6
a2 = a1[::2] + a1[1::2]
for method in 'timeit', 'default_timer':
wins1 = wins2 = 0
for _ in range(50):
time1 = time2 = float('inf')
for _ in range(5):
if method == 'timeit':
t1 = timeit('for _ in a1: pass', 'from __main__ import a1', number=1)
t2 = timeit('for _ in a2: pass', 'from __main__ import a2', number=1)
else:
start = default_timer();
for _ in a1: pass
end = default_timer()
t1 = end - start
start = default_timer();
for _ in a2: pass
end = default_timer()
t2 = end - start
time1 = min(time1, t1)
time2 = min(time2, t2)
wins1 += time1 < time2
wins2 += time2 < time1
print(f'timing method: timeit.{method}')
print(f' list a1 won {wins1} times')
print(f' list a2 won {wins2} times')
print()