用timeit对同一段代码分别做number=1的单次测速和number=100000,repeat=5的多轮测速,看单次测速有多不靠谱,正确用法该怎么设置参数。
最常见的timeit误用就是number=1,觉得"跑一次看看多快"就够了。
代码import timeit for _ in range(3): print(timeit.timeit("sum(range(100))", number=1))
代码完全没变,环境也没有人为制造干扰。
结果single-run(number=1) samples: 1.70909333974123e-06 7.080379873514175e-07 5.00003807246685e-07
三次结果是1.71微秒、0.71微秒、0.50微秒——最大值和最小值差了3.4倍,全部来自操作系统调度、CPU缓存状态、Python解释器内部状态这些存在但你控制不了的噪声,单次耗时本身短到跟这些噪声在同一个量级,噪声完全淹没了信号。
timeit推荐的用法是repeat=多轮,每轮number设置得足够大再取最小值。
结果timeit.repeat("sum(range(100))", number=100000, repeat=5) → [0.02786, 0.02806, 0.02817, 0.02839, 0.02846]
这5轮结果彼此只相差不到3%,远比number=1的3.4倍波动稳定得多——number=100000把单次运行的耗时(约0.28微秒/次)放大到能跟噪声区分开的量级,repeat=5取多轮里的最小值,则是为了排除"某一轮恰好被系统调度打断"这类偶发的额外干扰,官方文档也建议用min()而不是mean(),因为额外的干扰只会让某一轮变慢,不会让某一轮变得比速度更快。
用一个什么都不做的pass语句测100万次循环。
结果timeit.timeit("pass", number=1000000) = 0.0031秒 换算成单次:约3.1纳秒/次
每一步都是本文上面用timeit跑出来的原始结果。
timeit.timeit / timeit.repeat:对比number=1和大number+repeat的稳定性差异