【问题标题】:Compiler time in ipython3ipython3 中的编译器时间
【发布时间】:2015-02-13 20:56:51
【问题描述】:

执行命令,

timeit a = (3**(10**7))%24;

在 ipython3 上得到输出,

100000000 loops, best of 3: 13.5 ns per loop
Compiler time: 3.39 s

编译时间是指ipython3中JIT编译器所用的时间吗?

在 Ubuntu 14.04 上使用 ipython3 v1.2.1。

【问题讨论】:

    标签: python-3.x ipython jit timeit


    【解决方案1】:

    IPython 不实现任何类型的 JIT 编译器。 “编译器时间”表示 Python 将文本代码编译为 Python 字节码的时间。

    您的时间安排让我感到惊讶 - 这是一个非常简单的表达式,编译几乎不需要时间。如果小于 0.1 秒,IPython 不会报告编译器时间,而且我以前从未见过它出现过。于是我自己去试了一下,果然……

    In [2]: timeit a = (3**(10**7))%24;
    10000000 loops, best of 3: 20.7 ns per loop
    Compiler time: 5.54 s
    

    那么发生了什么?

    答案是 CPython 的窥视孔优化器,特别是函数 fold_binops_on_constants(),找到了 here (C code)10**7 是对两个常量的二元运算,保证始终具有相同的值。因此 Python 会预先计算该值,并将程序中的 10**7 替换为常量 10000000。但是现在3**10000000 是对两个常量的二元运算,所以它也计算了它。最后它对操作的最后部分做同样的事情,所以字节码看起来像这样:

    In [11]: dis.dis("a = (3**(10**7))%24")
      1           0 LOAD_CONST               7 (9)
                  3 STORE_NAME               0 (a)
                  6 LOAD_CONST               4 (None)
                  9 RETURN_VALUE
    

    当您的代码运行时,它实际上所做的只是将常量 9 存储在名称 a! 中!

    这对实际代码很有帮助 - 该表达式是在创建 .pyc 文件时预先计算的,因此每次运行程序时可以节省几秒钟。它对计时没有太大帮助,因为您的实际计算只由编译器运行一次。为了强制它进行计时,我们可以简单地将表达式的最里面部分设为变量,这样 Python 就不会对其进行优化(窥视孔优化器非常基础,与现代 C 编译器或 JIT 编译器完全不同):

    In [5]: b = 7
    
    In [6]: timeit a = (3**(10**b))%24;
    1 loops, best of 3: 5.5 s per loop
    

    【讨论】:

    • 谢谢@Thomas K。您是从哪里了解到窥视孔优化器的?你的系统配置是什么?
    • 我不记得我是从哪里了解到它的 - 如果您想了解更多信息,似乎有一两篇关于它的博客文章。我的系统正在运行 Debian,但我认为这与 Python 字节码编译无关。
    猜你喜欢
    • 2012-01-24
    • 2015-02-11
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多