Python timeit 无法工作?

3 投票
3 回答
4733 浏览
提问于 2025-04-16 14:43

有人能告诉我为什么会这样吗?

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完全一样,但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 个回答

0

这样会导致错误,把任何注释放在 %%timeit 之前:

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

改成这样,块的开头直接用 %%timeit

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

我猜问题出在你给timeit描述问题的方式上。我觉得发生的情况是,这个表达式在测试表达式编译时只被计算了一次,然后在每次timeit循环中只是被查看,而不是重新计算。所以现在你测量的只是赋值所花的时间,而不是实际的计算时间。

你需要强制每次都进行计算:

timeit.timeit('x = 10; y = 100; z = x ** y')

补充:针对你后来的问题,函数体正在被优化。编译器看到10*100000,意识到这个值永远不会改变,所以在编译时就计算出来了,而不是在运行时计算。

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 的表现是正常的。

撰写回答