Python的timeit无法工作?

3
有人能解释一下为什么会发生这种情况吗?
aatiis@aiur ~ $ time python /usr/lib64/python2.7/timeit.py -n 1 \
    -- 'x = 10**1000'
1 loops, best of 3: 0.954 usec per loop

real    0m0.055s
user    0m0.050s
sys     0m0.000s

aatiis@aiur ~ $ time python /usr/lib64/python2.7/timeit.py -n 1 \
    -- 'x = 10**100000'
1 loops, best of 3: 0.954 usec per loop

real    0m0.067s
user    0m0.040s
sys     0m0.020s

aatiis@aiur ~ $ time python /usr/lib64/python2.7/timeit.py -n 1 \
    -- 'x = 10**10000000'
1 loops, best of 3: 0.954 usec per loop

real    0m20.802s
user    0m20.540s
sys     0m0.170s

我使用timeit得到了完全相同的结果,但是time告诉我计算10**10000000需要超过20秒。如果我从解释器中调用timeit也会发生同样的情况:

>>> t = time.time()
>>> print timeit.timeit('x = 10**10000000;', number=1)
5.00679016113e-06
>>> print time.time() - t
20.6168580055

为什么我的timeit无法工作,或者我做错了什么?

额外信息:

>>> print sys.version
2.7.1+ (2.7:4f07cacb2c3b+, Mar 28 2011, 23:11:59)
[GCC 4.4.5]

>>> print sys.version_info
>>> sys.version_info(major=2, minor=7, micro=2, releaselevel='alpha', serial=0)

更新:

另外还有一个非常有趣的观察:

>>> def run():
...     t = time.time()
...     x = 10**10000000
...     print time.time() - t

当我定义这个函数后按下回车键,需要大约半分钟才能回到提示符。然后会显示:
>>> run()
2.14576721191e-06

为什么会发生这种情况?函数体被预编译或优化了吗?
3个回答

5
我猜问题在于您向timeit表达问题的方式。我认为正在发生的是,在编译测试表达式时,表达式被评估一次,然后每个timeit循环只是查看它(而不是重新评估)。因此,目前您测量的只是执行赋值所需的时间,而不是计算时间。
您需要强制每次进行计算:
timeit.timeit('x = 10; y = 100; z = x ** y')

编辑:回答你的后续问题,函数体正在被优化。编译器看到 10*100000 并意识到它永远不会改变,因此在编译时计算而不是运行时计算。


你说得对,每次强制计算确实会使它变慢。我不知道Python会为我预先计算表达式。 - Attila O.
@Attila - 直到现在我也不知道。 - David Webb

4

对比:

>>> import dis
>>> def run():
...     return 10**100
... 
>>> dis.dis(run)
  3           0 LOAD_CONST               3 (100000000000000000000000000000000000
00000000000000000000000000000000000000000000000000000000000000000L)
              3 RETURN_VALUE        

并且

>>> def runvar():
...     x = 10
...     return x**100
... 
>>> dis.dis(runvar)
  3           0 LOAD_CONST               1 (10)
              3 STORE_FAST               0 (x)

  4           6 LOAD_FAST                0 (x)
              9 LOAD_CONST               2 (100)
             12 BINARY_POWER        
             13 RETURN_VALUE        

请注意,BINARY_POWER仅在第二种情况下在运行时执行。因此,timeit的行为符合预期。

0

这会导致错误,请在%%timeit之前添加任何注释:

#Example.......
%%timeit
df['distance'] = haversine_looping(df)

不要这样做,用%%timeit开始代码块:

%%timeit
df['distance'] = haversine_looping(df)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接