使用time.time()的奇怪定时问题

时间:2014-02-08 04:17:05

标签: python time timing

当我运行此代码时:

t0time = time.time() 

print 2**100000 #hundred thousand

t1time = time.time() 
print (t1time - t0time)*1000,"ms"

和这段代码:

t0time = time.time() 

print 2**1000000 #million

t1time = time.time() 
print (t1time - t0time)*1000,"ms"

他们输出     70.0349807739 ms     6865.22507668 ms 分别。但是当我不打印值时,用print x替换a = x行,我得到相同的输出,     0.00119209289551毫秒 对于两者而言,虽然他们采取明显不同的时间这是为什么?

2 个答案:

答案 0 :(得分:1)

当你不打印时,它非常快。 0.00119209289551 ms是time.time()可以捕获的最小'tick'。

因此报告均为0.00119209289551 ms。

准确估计速度。计算超过100,000个循环并比较总时间。

现在,如果似乎需要更长时间,例如,如果你自己计算时间,那么这就是可能发生的事情:

Python正在看到值2 ** 1000000并且说“嘿,那不是使用变量或任何东西,所以我可以在代码'运行'之前预先计算它。”很多语言都会这样做,他们会将3 * 5这样的东西转换为15,因为,嘿,为什么不呢?不妨节省计算能力。

所以等待的时间是python在程序运行之前花费“预先计算”值的时间。未设置t0time,因为脚本尚未运行。我不是python专家,但这就是很多语言,无论是脚本还是编译的,都是如此。

答案 1 :(得分:1)

检查简单表达式花费多少时间的正确方法是使用timeitIPython

特别方便
In [6]: %timeit 2**100000
100000000 loops, best of 3: 16.4 ns per loop

In [7]: %timeit 2**1000000
100000000 loops, best of 3: 16.4 ns per loop

In [8]: %timeit 2**100000000
100000000 loops, best of 3: 16.4 ns per loop
Compiler time: 0.64 s

注意所花费的时间是如何恒定的(16.4 纳秒。这是将任何常量加载到堆栈中所花费的时间)。但请注意最后一个语句如何显示Compiler time: 0.64s。因此,正如已经观察到的那样,计算由编译器执行,而不是在运行时执行。在最后一个例子中,数字太大,编译时间很长,因此IPython也会显示它。

如果我们尝试更大的数字,您会发现编译时间是唯一发生重大变化的时间:

In [9]: %timeit 2**1000000000
100000000 loops, best of 3: 16.4 ns per loop
Compiler time: 8.62 s

我们可以另外确认正在发生的事情,直接查看编译器使用dis模块生成的字节码:

In [10]: import dis
    ...: dis.dis(lambda: 2**100000)
    ...: 
  2           0 LOAD_CONST               3 (999002093014384507944032764330033590  ... MANY more digits ... 396223208402597025155304734389883109376) 
              3 RETURN_VALUE   

正如您所看到的,代码包含任何计算结果的BINARY_POWER运算符。我们对timeit所做的时间只是对LOAD_CONST操作进行计时,该操作需要相同的时间,与数字的大小无关。

如果我们尝试反汇编使用参数的程序,我们在运行时获取计算:

In [12]: dis.dis(lambda x: x**2)
  1           0 LOAD_FAST                0 (x) 
              3 LOAD_CONST               1 (2) 
              6 BINARY_POWER         
              7 RETURN_VALUE   

此优化由窥孔优化器执行,仅适用于常量。甚至代码简单如下:

In [13]: def function():
    ...:     a = 2
    ...:     return a ** 100000

优化,虽然它看起来完全等同于使用return 2 ** 100000

In [14]: dis.dis(function)
  2           0 LOAD_CONST               1 (2) 
              3 STORE_FAST               0 (a) 

  3           6 LOAD_FAST                0 (a) 
              9 LOAD_CONST               2 (100000) 
             12 BINARY_POWER         
             13 RETURN_VALUE    

另请注意,打印一个数字的时间与其大小成正比! 2**100000有大约30k的数字,而2**1000000有大约30万个数字!打印后者需要花费大约10倍的时间来打印前者(并且您的时间确认这一点!)。