Python timeit的两个非常不同但非常一致的结果

时间:2013-09-01 18:49:21

标签: python performance generator list-comprehension

在一个有点人为的实验中,我想将Python的一些内置函数与numpy函数进行比较。当我开始计时时,我发现了一些奇怪的东西。

当我写下以下内容时:

import timeit
timeit.timeit('import math; math.e**2', number=1000000)

我会以极其统计上显着的方式在几乎随机的交替中得到两个不同的结果。

这在2秒和0.5秒之间交替。

这让我很困惑,所以我做了一些实验来弄清楚发生了什么,我只是更加困惑。所以我尝试了以下实验:

[timeit.timeit('import math; math.e**2', number=1000000) for i in xrange(100)]

完全导致了0.5的数字。然后我尝试用发电机播种:

test = (timeit.timeit('import math; math.e**2', number=1000000) for i in xrange(100))
[item for item in test]

导致列表完全填满了2.0号。

根据alecxe的建议,我将时间表改为:

timeit.timeit('math.e**2', 'import math', number=1000000)

同样在大约0.1到0.4秒之间交替,但是当我重新比较生成器和列表推导的实验时,但这次结果被翻转了。也就是说,生成器表达式经常出现0.1秒的数字,而列表理解返回0.4秒的完整列表。

直接控制台输出:

>>> test = (timeit.timeit('math.e**2', 'import math', number=1000000) for i in xrange(100))
>>> test.next()
0.15114784240722656

>>> timeit.timeit('math.e**2', 'import math', number=1000000)
0.44176197052001953
>>> 

编辑:我正在使用运行dwm的Ubuntu 12.04,我在xterm和gnome-terminal中都看到了这些结果。我正在使用python 2.7.3

有人知道这里发生了什么吗?这对我来说似乎很奇怪。

1 个答案:

答案 0 :(得分:0)

事实证明这里发生了一些事情,虽然这些怪癖中显然有一些我特定于我的机器,但是我认为值得张贴它们以防万一有人对同样的事情感到困惑。

首先,两个时间函数之间的区别在于:

timeit.timeit('math.e**2', 'import math', number=1000000)

导入语句被延迟加载。如果您尝试以下实验,这一点就很明显了:

timeit.timeit('1+1', 'import math', number=1000000)

timeit.timeit('1+1', number=1000000)

因此,当它直接在列表推导中运行时,看起来这个import语句正在为每个条目加载。 (确切的原因可能与我的配置有关。)

过去,回到最初的问题,看起来3/4的时间实际上花了导入数学,所以我猜测当生成等式时,迭代之间没有缓存存储,而那里是列表理解中的导入缓存(再次,这可能是配置特定的确切原因)