【问题标题】:How does this internal Python optimization work for mathematical expressions?这种内部 Python 优化如何适用于数学表达式?
【发布时间】:2017-12-28 14:59:09
【问题描述】:

这是一个优化问题。我在函数中有一个表达式,如下所示:

>>> def x():
...     num = 2 * 4 * 100 * 20
...
>>> x.__code__.co_consts
(None, 2, 4, 100, 20, 8, 800, 16000)

表达式2 * 4 * 100 * 20的结果是16000,所以如果我们反汇编x

>>> dis.dis(x)
  2           0 LOAD_CONST               7 (16000)
              3 STORE_FAST               0 (x)
              6 LOAD_CONST               0 (None)
              9 RETURN_VALUE       

16000 几乎是我们所需要的。 co_consts 商店 8 和 800 从技术上讲不再需要,我们有总数吗?

将上述表达式与另一个表达式进行比较:

>>> def x():
...     num = 3 + 4 + 9  * 4
... 
>>> x.__code__.co_consts
(None, 3, 4, 9, 7, 36)

看起来字节码编译器接受二进制操作数并存储它们的计算值:

9 * 4   36 
3 + 4   7 

反汇编函数:

>>> dis.dis(x)
  2           0 LOAD_CONST               4 (7)
              3 LOAD_CONST               5 (36)
              6 BINARY_ADD          
              7 STORE_FAST               0 (num)
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE   

有趣的是,如果您采用以下表达式:2 + 5 * 8 - 5 + 23 * 4co_consts 将是 (None, 2, 5, 8, 23, 4, 40, 92),仅计算乘法:5 * 823 * 4 忽略了加法和减法。

这种优化如何真正发挥作用?我仅在 2.7 上对此进行了测试。

【问题讨论】:

  • 您正在目睹一些窥视孔优化技巧。查看peephole.c

标签: python optimization python-internals


【解决方案1】:

没有解释这一点 ;-) 这意味着它是一个完全反映实现细节的黑暗角落。无论好坏,负责的“窥孔优化器”不是在程序的解析树上工作,而是在生成的字节码上工作。这使用起来很笨拙,因此很难预测会发生什么,并且它会随着版本的变化而变化。例如这里在 Python 3.6.1 下:

>>> def f():
...     return 2 + 5 * 8 - 5 + 23 * 4
>>> f.__code__.co_consts
(None, 2, 5, 8, 23, 4, 40, 42, 37, 92, 129)
>>> import dis
>>> dis.dis(f)
  2           0 LOAD_CONST              10 (129)
              2 RETURN_VALUE

所以表达式被折叠到它的最终值,但所有中间值都留在了常量元组中。

@COLDSPEED 已经在他们的评论中链接到源代码,任何关于它的问题的唯一真正答案必须来自您正在运行的 CPython 版本中使用的peephole.c。随着时间的推移,它逐渐变得更加雄心勃勃,但背后并没有真正的计划。

【讨论】:

    猜你喜欢
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多