python 的 `timeit` 并不总是与数字成线性比例?
python's `timeit` doesn't always scale linearly with number?
我是 运行 Python 2.7.10,16GB,2.7GHz i5,OSX 10.11.5 机器。
我在许多不同类型的示例中多次观察到这种现象,因此下面的示例虽然有点做作,但具有代表性。当我的好奇心终于被激起时,这正是我今天早些时候碰巧在做的事情。
>>> 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。
我可以做更多的临时数据收集,但此时我还没有想到一个假设。
关于为什么在某些中间运行次数处出现非线性标度的任何概念?
这与较少的运行次数有关,不够准确,无法获得您想要的计时分辨率。
随着运行次数的增加,时间之间的比率接近运行次数之间的比率:
>>> 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
我是 运行 Python 2.7.10,16GB,2.7GHz i5,OSX 10.11.5 机器。
我在许多不同类型的示例中多次观察到这种现象,因此下面的示例虽然有点做作,但具有代表性。当我的好奇心终于被激起时,这正是我今天早些时候碰巧在做的事情。
>>> 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。
我可以做更多的临时数据收集,但此时我还没有想到一个假设。
关于为什么在某些中间运行次数处出现非线性标度的任何概念?
这与较少的运行次数有关,不够准确,无法获得您想要的计时分辨率。
随着运行次数的增加,时间之间的比率接近运行次数之间的比率:
>>> 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