【问题标题】:Inconsistency between %time and %timeit in IPythonIPython 中 %time 和 %timeit 之间的不一致
【发布时间】:2011-12-23 17:55:07
【问题描述】:

我遇到了一个我无法解释的奇怪情况。这是我生成大量元组的测试时间:

In [1]: def get_list_of_tuples():
   ...:     return [(i,) for i in range(10**6)]
   ...:

In [2]: %time res = get_list_of_tuples()
CPU times: user 0.93 s, sys: 0.08 s, total: 1.01 s
Wall time: 0.98 s

In [3]: %timeit res = get_list_of_tuples()
1 loops, best of 3: 92.1 ms per loop

如您所见,生成这个庞大的元组列表只需要不到一秒钟的时间。 timeit 报告执行时间约为 0.1 秒。为什么两份报告的差异如此之大?

(在 IPython 0.11、Python 2.6.5 上测试。)

【问题讨论】:

  • 如果先运行 %timeit 再运行 %time 会得到相同的结果吗?
  • 有趣的评论。是的,我得到了类似的结果,但执行顺序相反。
  • 我不知道 IronPython,所以我对%time%timeit 不能多说,但我猜%time 会重复计时测试10 次。
  • 我使用的不是IronPython,而是IPython。 %timeit 也是多次执行命令的函数,而不是 %time。
  • %timeit 在 3 次运行中取得了最好的成绩,那么:for i in range(3): %time res=get_list_of_tuples() 得到了什么?出于这个原因,%timeit 报告较小的数字是正常的(我通常看到 ~2x),但 10x 很多。我不认为你在 Windows 上?

标签: python ipython timeit


【解决方案1】:

主要区别在于“by default, timeit() temporarily turns off garbage collection during the timing”。

开启垃圾收集返回的结果与问题中显示的结果相似,即有垃圾收集的执行时间比没有垃圾收集的执行时间大:

In [1]: import timeit

# Garbage collection on.
In [2]: N = 10; timeit.timeit('[(i,) for i in range(10**6)]', 'gc.enable()', number=N) / N
Out[2]: 0.74884700775146484
# 749 ms per loop.

# Garbage collection off.
In [3]: N = 10; timeit.timeit('[(i,) for i in range(10**6)]', number=N) / N
Out[3]: 0.15906109809875488
# 159 ms per loop.

【讨论】:

    【解决方案2】:

    伯努瓦,

    如果我使用 Python 2.6.6 和 IPython 0.10,那么我会看到与您类似的答案。使用 Python 2.7.1 和 IPython 0.10.1 我得到了一些更明智的东西:

    % ipython
    Python 2.7.1 (r271:86832, Nov  3 2011, 16:23:57) 
    Type "copyright", "credits" or "license" for more information.
    
    IPython 0.10.1 -- An enhanced Interactive Python.
    
    In [1]: def get_list_of_tuples():
       ...:     return [(i,) for i in range(10**6)]
       ...: 
    
    In [2]: %time res = get_list_of_tuples()
    CPU times: user 0.25 s, sys: 0.10 s, total: 0.35 s
    Wall time: 0.35 s
    
    In [3]: %timeit res = get_list_of_tuples()
    1 loops, best of 3: 215 ms per loop
    

    【讨论】:

    • 使用 IPython 0.11 和 Python 2.7.2 得到非常相似的结果。
    【解决方案3】:

    %time - 语句只运行一次,并且有测量错误

    %timeit - 运行语句几次,并选择最准确的时间。

    请参阅Python timeit module documentation 了解一些说明

    【讨论】:

    • "RTFM" 不是我问题的答案。如果我生成 1000 万个而不是 100 万个元组的列表,%time 报告 56 秒,%timeit 报告 882 毫秒。这不正常,我想知道为什么。
    • @badzil,您是否尝试过手动执行 %time 几次?结果是一样的吗?如果您同时拥有 2.6 和 2.7,请尝试反汇编并找出生成代码之间的差异(我只有 2.7)
    • 如果我运行 %time 和 %timeit 几次,结果是一致的。能否详细说明生成的代码?
    • @badzil,我无法重现您的奇怪结果。关于生成的代码,我的意思是import dis; dis.dis(generate_list_of_tuples)。 Python 2.6 产生了一些额外的指令code at pastebin,但这不应该对时间造成太大影响。老实说我不知道​​这种不一致的原因,也许它与 2.6 中的垃圾收集器有某种关系,但这只是一个猜测。
    猜你喜欢
    • 2013-01-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    相关资源
    最近更新 更多