python 3.11 正式发布,有哪些新特色?(1/5)python 3.11 的第二个改进特点:代码执行速度更快 python是一种执行速度较慢的编程语言,这好像已经是业内对python的共同观点。例如,python语言中的循环比类似的C语言写成的循环,执行速度慢不止一个数量级。但一般来说,编程语言的开发效率比代码的执行速度更重要,python能使用很多扩展工具包,而这些工具包都是用执行速度比较快的语言开发的,如科学计算工具包Numpy就比python本身内置的计算方法快很多,也因为学习python编写代码更容易,使得python在数据科学领域有长足的应用。但python官方并没有忽略python代码执行速度慢的缺点,于2020年提出了改进性能的 Shannon 计划,按这份计划的要求,python代码未来的执行速度要比当年发布的版本提高5倍以上,并且确定在更快地 CPython的基础上进行改进。 在官方声明文件 PEP 659中,描述了一个个性化的自适应解释器,其主要思想就是在提高代码执行速度的同时,对代码中经常出现的一些操作进行优化,且转换后的python二进制代码可以即时做出适应或改变,这和JIT(Just-in-time)编译的理念类似。众所周知,python代码在运行之前要被解释器编译为二进制代码,而二进制代码是由更多的基本指令组成,这些指令要比规范的python代码更多,因此每一行python代码都会转换为几个二进制代码语句。针对这个问题,看看下面的示例:>>> def feet_to_meters(feet): ... return 0.3048 * feet ... 上面这个函数,可以使用 dis 对该函数做反汇编处理,>>> import dis >>> dis.dis(feet_to_meters) 1 0 RESUME 0 2 2 LOAD_CONST 1 (0.3048) 4 LOAD_FAST 0 (feet) 6 BINARY_OP 5 (*) 10 RETURN_VALUE 上面是运行 dis.dis 函数后的结果, 可以看出每一行都是一个二进制代码指令,指令信息由五列,包括行号、字节地址、操作代码名称、操作参数和圆括号中的参数解释。对于编写python代码来说,不需要了解这样的细节,这里拿出来只是为了说明python运行的内在机制。提高python代码的执行速度所在的环节就在python代码转换并生成二进制代码这一步,获得了代码运行过程中可以被优化的指令,就可以用自适应指令来替代。当一个函数被调用的次数确定了,加速机制即刻实施。 可以进一步探究一下解释器如何通过调用 dis() 函数和 设置 adaptive 参数,来实现与二进制代码的自适应。看看下面的例子,定义一个函数,调用几次,其参数是一个浮点数:>>> def feet_to_meters(feet): ... return 0.3048 * feet ... >>> feet_to_meters(1.1) 0.33528 >>> feet_to_meters(2.2) 0.67056 >>> feet_to_meters(3.3) 1.00584 >>> feet_to_meters(4.4) 1.34112 >>> feet_to_meters(5.5) 1.6764000000000001 >>> feet_to_meters(6.6) 2.01168 >>> feet_to_meters(7.7) 2.34696 接下来,看看 函数 feet_to_meters()运行7次后,该函数的二进制代码指令信息是什么样,>>> import dis >>> dis.dis(feet_to_meters, adaptive=True) 1 0 RESUME 0 2 2 LOAD_CONST 1 (0.3048) 4 LOAD_FAST 0 (feet) 6 BINARY_OP 5 (*) 10 RETURN_VALUE 从上面的运行结果中,看出有什么特别之处,函数feet_to_meters带参数和前面示例中不带参数的情况下,二进制代码的指令信息相同。接下来再运行一次,这是第8次运行该函数,看看该函数的二进制代码的指令信息发生了什么变化:>>> feet_to_meters(8.8) 2.68224 >>> dis.dis(feet_to_meters, adaptive=True) 1 0 RESUME_QUICK 0 2 2 LOAD_CONST__LOAD_FAST 1 (0.3048) 4 LOAD_FAST 0 (feet) 6 BINARY_OP_MULTIPLY_FLOAT 5 (*) 10 RETURN_VALUE 可以看出,函数feet_to_meters() 被运行8次之后,原来的二进制指令已经被个性化的指令替代,如 BINARY_OP 被 BINARY_OP_MULTIPLY_FLOAT 替代,这能更快地计算两个浮点数相乘。即使参数 feet 是浮点数的情况下,feet_to_meters()函数被实施了优化,但是该函数在调用其他类型的参数时依然执行替换后的二进制指令;尽管内在操作发生了改变,但python代码的执行和python 3.11之前的版本完全一样。 再看看下面的例子,连续调用该函数多次,参数feet 用整数:>>> for feet in range(52): ... feet_to_meters(feet) ... >>> dis.dis(feet_to_meters, adaptive=True) 1 0 RESUME_QUICK 0 2 2 LOAD_CONST__LOAD_FAST 1 (0.3048) 4 LOAD_FAST 0 (feet) 6 BINARY_OP_MULTIPLY_FLOAT 5 (*) 10 RETURN_VALUE python解释器还是意在完成两个浮点数相乘这一操作,源代码转换为二进制代码指令集都是相同的。以上示例通过不同的参数类型表明,python 3.11在改变已有代码时无需考虑代码的执行速度。 python 3.11是在更快的CPython项目的基础上改进代码执行速度,但CPython有两个重要的原则:该项目的任何重大改变都不会引入到python,即python可以基于CPython改善执行速度,但不是说CPython的所有重大改进都会被引入到pythonCPython的绝大部分代码都将会改进 这一点上有一个标准:CPython 3.11 比 CPython 3.0 平均快25%。因此,使用python 3.11应该更关注如何改进代码本身,而不是CPython 3.11 和 python 3.11 的标准之别。 CPython项目一直都在持续改进,其中有几个方面的优化将在2023年10月发布的Python 3.12中引入,该项目非常庞大,将涉及到python的所有方面。个性化的自适应解释器只是改进的内容之一。