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

Sla*_*off 6 python performance list-comprehension generator

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

当我写下面的内容时:

import timeit
timeit.timeit('import math; math.e**2', number=1000000)
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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

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

这导致了一个完整的2.0号码列表.

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

timeit.timeit('math.e**2', 'import math', number=1000000)
Run Code Online (Sandbox Code Playgroud)

类似地在大约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
>>> 
Run Code Online (Sandbox Code Playgroud)

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

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

Sla*_*off 1

事实证明,这里发生了一些事情,虽然显然其中一些怪癖是我的机器特有的,但尽管如此,我认为还是值得将它们发布出来,以防有人对同样的事情感到困惑。

首先,两个 timeit 函数之间的不同之处在于:

timeit.timeit('math.e**2', 'import math', number=1000000)
Run Code Online (Sandbox Code Playgroud)

import 语句是延迟加载的。如果您尝试以下实验,这一点就会变得显而易见:

timeit.timeit('1+1', 'import math', number=1000000)
Run Code Online (Sandbox Code Playgroud)

相对:

timeit.timeit('1+1', number=1000000)
Run Code Online (Sandbox Code Playgroud)

因此,当它直接在列表理解中运行时,看起来好像为每个条目加载了这个导入语句。(具体原因可能与我的配置有关)。

除此之外,回到最初的问题,看起来 3/4 的时间实际上花在了导入数学上,所以我猜测当生成方程时,迭代之间没有缓存存储,而有导入缓存在列表理解中(同样,其确切原因可能是特定于配置的)