Python3.13的JIT是如何实现的

去年圣诞节前,CPython的core dev向世界宣布了一条令人振奋的消息,即Python虚拟机可以以JIT的形式执行字节码。

什么是JIT

JIT(Just In Time)是一个老生常谈的话题了。通俗来讲,JIT是指虚拟机可以将IR(比如Python字节码)编译成机器能理解的机器码,从而加速程序运行。这里的Time应该理解成Runtime,也就是说在运行期间生成了机器码并执行的方式就算JIT,这区别于传统的先编译后执行的AOT方式。

在Python3.13中,虚拟机仍然会读取前端生成的字节码,但是不是解释执行,而是翻译成CPU能理解的机器码让CPU执行。由于是机器指令,所以程序的执行效率会比C语言代码快得多。

然而,CPython的JIT实现起来并不简单。由于CPython的字节码过于"动态",直接翻译成静态的机器码难度非常大。在本次PR的作者Brandt Bucher的演讲中,他总结了三点困难,一是去掉解释器架构(overhead)、二是静态编译优化的字节码(原文是trace,指一次运行中执行到的字节码)、三是映射成机器码(即reduce indirection)。

什么是微指令(UOP)

CPython的JIT不是一个PR就能实现的,它需要前面版本提供的微指令支持。其实在去年7月份,CPython就加入了微指令的概念。它是将基本的字节码再次拆分成粒度更细的原子操作 ,也就是微指令。举一个例子,当python程序执行到了字节码JUMP_BACKWARD,它会往回跳转到某个已经执行过的字节码。但是这个跳转指令也可以拆分成更详细的微指令。比如跳回当前trace的顶部,那它会被替换为JUMP_TO_TOP微指令。比如跳到当前trace外的其他地方,它会被替换为SAVE_IPEXIT_TRACE两个微指令。

虽然JUMP_BACKWARDSAVE_IP都是字节码,但是已经不是一个维度了。处于粒度更细的维度叫做Tire2字节码,反之是Tire1字节码。

什么是copy-and-patch

copy-and-patch是实现JIT的一种方式。它是一种通过指令模板的方式简化经常执行的Tire2字节码。所谓的指令模板就是一些预设的机器码,当解释器在第一次执行代码的时候会观察有哪些字节码是循环调用的,这样在后续执行中它们会被替换成预设的机器码以提升速度。

比如LOAD_FAST字节码对应的是这样的C代码------

我们把精髓提取出来做成模板(注意相似代码部分)------

然后再把这部分代码转换成机器码------

最后,再把这些机器码重新织入CPython中------

这样,在CPython中可以直接执行机器码了,远远快于原本的C语言代码。

实操

为了感受一下CPython的JIT,我租了一台Ubuntu22.04。

首先,需要安装LLVM,而且必须是LLVM-16。最快的方法是在GitHub上下载编译好的安装包。

ruby 复制代码
wget https://github.com/llvm/llvm-project/releases/download/llvmorg-16.0.4/clang+llvm-16.0.4-x86_64-linux-gnu-ubuntu-22.04.tar.xz

然后解压安装包,在目录bin内有现成的clang-16。将其配置成环境变量。

其次,准备一个bootstrap的Python。 因为CPython项目内有很多代码是靠Python脚本生成的,所以需要一个低版本的Python来生成这些代码。这里建议使用Python3.11以上的Python作为bootstrap Python,因为更低版本的Python有些脚本运行不了。

然后运行以下指令

go 复制代码
./configure --enable-experimental-jit
make
make install

这样,你就拥有了一个支持JIT的python。接下来下载pip------

arduino 复制代码
wget https://bootstrap.pypa.io/get-pip.py
python3.13 get-pip.py

用pip安装pyperformance,并跑测试用例------

arduino 复制代码
python3.13 -m pip install pyperformance
python3.13 -m pyperformance run -o py313-jit.json

同样用常规版本的Python3.13跑相同的测试用例,并比较它们------

vbnet 复制代码
python -m pyperformance compare py313.json py313-jit.json

Emmm,几乎都是变慢的。所以说运行速度并没有提升,就像Brandt Bucher说的,这个只是实验版本,如果效果不好的话完全可以在未来版本中删去这个功能。目前,也是在考虑不断优化提升这些微指令模板。

参考资料

Youtube链接:link.zhihu.com/?target=htt...

Github PR:link.zhihu.com/?target=htt...

pyperformance链接:link.zhihu.com/?target=htt...

相关推荐
_平凡之路_5 分钟前
解决ubuntu22.04 gnome-terminal 无法启动的问题
linux·运维·python
豆本-豆豆奶8 分钟前
23个Python在自然语言处理中的应用实例
开发语言·python·自然语言处理·编程语音
NiNg_1_23412 分钟前
机器学习之Python中Scikit-Learn(sklearn)入门
python·机器学习·scikit-learn
你可以自己看30 分钟前
python中函数式编程与高阶函数,装饰器与生成器,异常处理与日志记录以及项目实战
服务器·开发语言·python
ymchuangke1 小时前
线性规划------ + 案例 + Python源码求解(见文中)
开发语言·python
鸠摩智首席音效师1 小时前
如何设置 Django 错误邮件通知 ?
python·django
优雅一只猫1 小时前
Pybullet 安装过程
python
秋秋秋叶1 小时前
Python学习——【3.1】函数
python·学习
Hello.Reader2 小时前
ClickHouse 与 Quickwit 集成实现高效查询
python·clickhouse·django·全文检索
技术无疆2 小时前
【Python】Anaconda插件:Sublime Text中的Python开发利器
ide·python·编辑器·pip·pygame·sublime text·python3.11