关于python:Python优化机制常量折叠

3次阅读

共计 1921 个字符,预计需要花费 5 分钟才能阅读完成。

英文:https://arpitbhayani.me/blogs…

作者:arprit

译者:豌豆花下猫(“Python 猫”公众号作者)

申明:本翻译是出于交流学习的目标,基于 CC BY-NC-SA 4.0 受权协定。为便于浏览,内容略有改变。

每种编程语言为了表现出色,并且实现卓越的性能,都须要大量编译器级的优化。

一种驰名的优化技术是“常量折叠”(Constant Folding):在编译期间,编译器会设法辨认出常量表达式,对其进行求值,而后用求值的后果来替换表达式,从而使得运行时更精简。

在本文中,咱们深入探讨了什么是常量折叠,理解了它在 Python 世界中的适用范围,最初解读了 Python 的源代码(即 CPython),并剖析出 Python 是如何优雅地实现它。

常量折叠

所谓常量折叠,指的是 在编译时 就查找并计算常量表达式,而不是 在运行时 再对其进行计算,从而会使运行时更加精简和疾速。

>>> day_sec = 24 * 60 * 60

当编译器遇到一个常量表达式时,如上所述,它将对表达式求值,并作替换。

通常而言,表达式会被“形象语法树”(Abstract Syntax Tree,简写为 AST)中的计算值所替换,然而这齐全取决于语言的实现。

因而,上述表达式能够等效地被执行为:

>>> day_sec = 86400

Python 中的常量折叠

在 Python 中,咱们能够应用 反汇编模块(Disassembler)获取 CPython 字节码,从而更好地理解代码执行的过程。

当应用 dis 模块反汇编上述常量表达式时,咱们会失去以下字节码:

>>> import dis
>>> dis.dis("day_sec = 24 * 60 * 60")

        0 LOAD_CONST               0 (86400)
        2 STORE_NAME               0 (day_sec)
        4 LOAD_CONST               1 (None)
        6 RETURN_VALUE

从字节码中能够看出,它只有一个LOAD_CONST,以及一个曾经计算好的值86400

这表明 CPython 解释器在解析和构建形象语法树期间,会折叠常量表达式 24 60 60,并将其替换为计算值 86400。

常量折叠的适应范畴

Python 会尝试折叠每一个常量表达式,但在某些状况下,即便该表达式是常量,然而 Python 并不会对其进行折叠。

例如,Python 不会折叠x = 4 ** 64,但会折叠 x = 2 ** 64

除了算术表达式,Python 还会折叠波及字符串和元组的表达式,其中,长度不超过 4096 的字符串常量表达式会被折叠。

>>> a = "-" * 4096   # folded
>>> a = "-" * 4097   # not folded
>>> a = "--" * 4096  # not folded

常量折叠的外部细节

当初,咱们将重点转移到外部的实现细节,即关注 CPython 在哪里以及如何实现常量折叠。

所有的 AST 优化(包含常量折叠)都能够在 ast_opt.c 文件中找到。根本的开始函数是 astfold_expr,它会折叠 Python 源码中蕴含的所有表达式。

这个函数以递归形式遍历 AST,并试着折叠每个常量表达式,如上面的代码片段所示:

astfold_expr 在折叠某个表达式之前,会尝试折叠其子表达式(操作对象),而后将折叠操作代理给特定的表达式折叠函数。

特定操作的折叠函数对表达式求值,并返回计算后的常数,而后将其放入 AST 中。

例如,每当 astfold_expr 遇到二值运算时,它便调用 fold_binop,递归地计算两个子操作对象(表达式)。

fold_binop 函数返回计算后的常量值,如上面的代码片段所示:

fold_binop 函数通过查看以后运算符的品种,而后调用其相应的处理函数来折叠二值运算。例如,如果以后的操作是加法运算,为了计算最终值,它会对其左侧和右侧操作数调用 PyNumber_Add。

怎么优雅?

为了无效地折叠某些模式或类型的常量表达式,CPython 不会写非凡的逻辑,而是调用雷同的通用代码。例如,在折叠时,它会调用通用的 PyNumber_Add 函数,跟执行惯例的加法操作一样。

因而,CPython 通过确保其通用代码 / 计算过程能够解决常量表达式的求值,从而打消了编写非凡函数来解决常量折叠的须要。

参考资料

  • 常量折叠 (https://en.wikipedia.org/wiki…
  • CPython 优化(https://stummjr.org/post/cpyt…
  • Python dis 模块与常量折叠(https://yasoob.me/2019/02/26/…
  • CPython 实现常量折叠的简略办法(https://utcc.utoronto.ca/~cks…
  • ​ AST 的常量折叠优化过程(https://bugs.python.org/issue…
正文完
 0