【问题标题】:python's `timeit` doesn't always scale linearly with number?python的`timeit`并不总是随数字线性缩放?
【发布时间】:2017-02-05 12:29:06
【问题描述】:

我在 16GB、2.7GHz i5、OSX 10.11.5 机器上运行 Python 2.7.10。

我在许多不同类型的示例中多次观察到这种现象,因此下面的示例虽然有点做作,但具有代表性。这正是我今天早些时候碰巧在做的事情,当时我的好奇心终于被激起了。

>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=100)
3.790855407714844e-05
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=1000)
0.0003371238708496094
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=10000)
0.014712810516357422
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=100000)
0.029777050018310547
>>> timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=1000000)
0.21139287948608398

您会注意到,从 100 到 1000,时间增加了 10 倍,正如预期的那样。但是,从 1e3 到 1e4,它更像是 50 的因数,然后是从 1e4 到 1e5 的 2 倍(所以从 1e3 到 1e5 的总因数是 100,这是预期的)。

我认为无论是在计时的实际过程中还是在 timeit 本身中,都必须进行某种基于缓存的优化,但我无法凭经验判断是否是这种情况。导入似乎并不重要,可以通过一个最基本的示例观察到这一点:

>>> timeit('1==1', number=10000)
0.0005490779876708984
>>> timeit('1==1', number=100000)
0.01579904556274414
>>> timeit('1==1', number=1000000)
0.04653501510620117

从 1e4 到 1e6 存在 1e2 时间差的真实因子,但中间步骤是 ~30 和 ~3。

我可以进行更多的临时数据收集,但目前我还没有想到任何假设。

关于为什么在某些中间运行次数处出现非线性比例的任何概念?

【问题讨论】:

  • 我没有具体的答案给你,但在这些小时间尺度上,很难确切知道环境(你的计算机)中可能发生的其他什么事情会导致时间波动。 .
  • 只需运行timeit('1==1', number=10000) 多次并观察波动。你基本上是在观察噪音。您的进程可能被其他进程抢占,或者计时器的分辨率可能不够高,无法准确解决如此短的时间。

标签: python performance optimization timeit


【解决方案1】:

这与较少的运行次数不足以获得所需的计时分辨率有关。

随着运行次数的增加,时间之间的比率会接近运行次数之间的比率:

>>> def timeit_ratio(a, b):
...     return timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=a) / timeit('unicodedata.category(chr)', setup = 'import unicodedata, random; chr=unichr(random.randint(0,50000))', number=b)
>>> for i in range(32):
...   r = timeit_ratio(2**(i+1), 2**i)
...   print 2**i, 2**(i+1), r, abs(r - 2)**2  # mean squared error
...
1 2 3.0 1.0
2 4 1.0 1.0
4 8 1.5 0.25
8 16 1.0 1.0
16 32 0.316455696203 2.83432142285
32 64 2.04 0.0016
64 128 1.97872340426 0.000452693526483
128 256 2.05681818182 0.00322830578512
256 512 1.93333333333 0.00444444444444
512 1024 2.01436781609 0.000206434139252
1024 2048 2.18793828892 0.0353208004422
2048 4096 1.98079658606 0.000368771106961
4096 8192 2.11812990721 0.0139546749772
8192 16384 2.15052027269 0.0226563524921
16384 32768 1.93783596324 0.00386436746641
32768 65536 2.28126901347 0.0791122579397
65536 131072 2.18880312306 0.0356466192769
131072 262144 1.8691643357 0.0171179710535
262144 524288 2.02883451562 0.000831429291038
524288 1048576 1.98259818317 0.000302823228866
1048576 2097152 2.088684654 0.00786496785554
2097152 4194304 2.02639479643 0.000696685278755
4194304 8388608 1.98014042724 0.000394402630024
8388608 16777216 1.98264956218 0.000301037692533

【讨论】:

  • 对此无可争辩。 (我会在几分钟后接受答案)
猜你喜欢
  • 1970-01-01
  • 2021-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-30
  • 1970-01-01
相关资源
最近更新 更多