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...

相关推荐
Chef_Chen7 分钟前
从0开始机器学习--Day17--神经网络反向传播作业
python·神经网络·机器学习
千澜空27 分钟前
celery在django项目中实现并发任务和定时任务
python·django·celery·定时任务·异步任务
斯凯利.瑞恩34 分钟前
Python决策树、随机森林、朴素贝叶斯、KNN(K-最近邻居)分类分析银行拉新活动挖掘潜在贷款客户附数据代码
python·决策树·随机森林
yannan201903131 小时前
【算法】(Python)动态规划
python·算法·动态规划
蒙娜丽宁1 小时前
《Python OpenCV从菜鸟到高手》——零基础进阶,开启图像处理与计算机视觉的大门!
python·opencv·计算机视觉
光芒再现dev1 小时前
已解决,部署GPTSoVITS报错‘AsyncRequest‘ object has no attribute ‘_json_response_data‘
运维·python·gpt·语言模型·自然语言处理
好喜欢吃红柚子1 小时前
万字长文解读空间、通道注意力机制机制和超详细代码逐行分析(SE,CBAM,SGE,CA,ECA,TA)
人工智能·pytorch·python·计算机视觉·cnn
小馒头学python1 小时前
机器学习是什么?AIGC又是什么?机器学习与AIGC未来科技的双引擎
人工智能·python·机器学习
神奇夜光杯2 小时前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
千天夜2 小时前
使用UDP协议传输视频流!(分片、缓存)
python·网络协议·udp·视频流