【问题标题】:Why does timeit report slower code as faster one?为什么 timeit 将较慢的代码报告为较快的代码?
【发布时间】:2023-04-17 08:38:02
【问题描述】:

我在 Debian Stretch 中使用 python 3.5 对此进行了测试。
我尝试了基准测试the "Avoiding dots" optimization
正如所料,the "Avoiding dots" optimization 确实快得多。
出乎意料的是,timeit 将较慢的代码报告为较快的代码。 是什么原因?

$ time python3 -m timeit -s "s=''" "s.isalpha()"
10000000 loops, best of 3: 0.119 usec per loop

real    0m5.023s
user    0m4.922s
sys 0m0.012s
$ time python3 -m timeit -s "isalpha=str.isalpha;s=''" "isalpha(s)"
1000000 loops, best of 3: 0.212 usec per loop

real    0m0.937s
user    0m0.927s
sys 0m0.000s

【问题讨论】:

  • 在这种情况下这是意料之中的:isalpha(s)s.isalpha() 所做的工作量相同,您可以在检查字节码时进行验证。只有当您可以避免整个操作时,“避免点”才有帮助。在这里,您可以权衡属性查找的参数。
  • 换句话说,timeit 不会说谎。如果它说某事没有更快,那么它就没有更快;)
  • @zvone。除非这是你的第一次跑步
  • @L3viathan 如果他们做同样多的工作,那为什么一个几乎是另一个的两倍?
  • 这里的“避免点”优化应该是s=''; f=s.isalpha,然后是f(),实际上在我的测试中速度是原来的两倍。

标签: python timeit debian-stretch


【解决方案1】:

timeit 在“慢”的情况下做了 10 倍的 迭代。它自适应地尝试更多迭代以找到平衡统计质量和等待时间的数字。

【讨论】:

  • 这是一个有效的,甚至是有价值的观察,但不能解释为什么一个时间出乎意料地少于另一个。
  • @MadPhysicist:上述问题是为什么timeit 不同意提问者的期望(这显然是由time“确认”关于优化的理论设定的)。这回答了这个问题,而不是关于为什么一个版本的代码实际上更快的根本问题。
【解决方案2】:

感谢Davis Herring's answer
让我们更详细地了解:
来自python3 -m timeit -h

If -n is not given, a suitable number of loops is calculated by trying
successive powers of 10 until the total time is at least 0.2 seconds.

通过计算详细信息进行验证:

$ time python3 -m timeit -v -s "s=''" "s.isalpha()"
10 loops -> 3.44e-06 secs
100 loops -> 1.29e-05 secs
1000 loops -> 0.000117 secs
10000 loops -> 0.00116 secs
100000 loops -> 0.0118 secs
1000000 loops -> 0.116 secs
10000000 loops -> 1.17 secs
raw times: 1.21 1.21 1.21
10000000 loops, best of 3: 0.121 usec per loop

real    0m4.992s
user    0m4.977s
sys 0m0.012s

所有x loops -> y secs 时间总和都用于确定合适的循环数。
“原始时间”行中的每个项目都是单次重复计时器结果(the -r option 确定“原始时间”行中的项目数)。
几乎所有时间都匹配:

>>> 3.44e-06+1.29e-05+0.000117+0.00116+0.0118+0.116+1.17+1.21+1.21+1.21
4.92909334
>>> 4.992-4.92909334
0.06290666000000034

【讨论】: