找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

4071

积分

0

好友

530

主题
发表于 1 小时前 | 查看: 3| 回复: 0

11% 的性能提升,比原计划提前一年完成。

如果只看这组数字,放在任何一个大型技术项目中可能都算不上石破天惊。但当你了解到,实现这个性能提升的团队,早在一年前就失去了主要资金支持,成员们一度在断薪的情况下为爱发电,整个项目命悬一线时,这个故事的分量就完全不同了。

这正是 Python 3.15 JIT 背后真实发生的故事。没有大公司的慷慨解囊,也没有奇迹般的商业收购,一群志愿者在 Savannah 家中的衣柜里(字面意义上的衣柜)架起了四台服务器,硬是将一个早期“甚至比解释器还慢”的“笑话”项目,变成了一个真正“能跑起来,并且更快”的工程奇迹。

Python 3.15 JIT 与解释器性能对比折线图

图为2026年3月17日的性能基准测试结果(越低越好)。数据显示,经过社区优化,JIT版本在多个基准测试模型上已稳定超越纯解释器。

从困境开始:金主撤资,JIT项目命悬一线

让我们先快速了解一下背景。JIT,即即时编译器(Just-In-Time compiler),它的核心思路是让 Python 在运行时动态地将字节码编译成机器码,理论上能带来数倍的性能提升。然而,理论与现实之间往往横亘着巨大的鸿沟。

大约八个月前,CPython 中的 JIT 实现还被视为一场“灾难”。当时的基准测试结果甚至比传统的解释器还要慢,社区中的失望和质疑声不绝于耳。雪上加霜的是,负责推动此事的 Faster CPython 团队在 2025 年失去了其主要赞助方。项目核心开发者们一夜之间从领薪水的雇员变成了纯粹的志愿者,整个项目的前景变得扑朔迷离。

就连项目的主要贡献者之一也在后来的博客中坦言:“我当时真的在怀疑,这个项目最终到底能不能带来任何实质性的速度提升。”

抱着死马当活马医的心态,他们决定将项目更彻底地向社区开放。坦白说,这步棋风险极高——JIT 编译器的开发向来是编译器领域的“高塔”,技术门槛足以让绝大多数开发者望而却步。

社区接盘:将“玄学”拆解成可拼装的“乐高”

团队做了一件非常聪明的事情:系统性降低项目的“巴士因子(bus factor)”。

什么是“巴士因子”?这是一个略带黑色幽默的指标,它衡量的是一个项目中有多少人被“巴士撞了”(即突然离开),项目就会陷入瘫痪。在此之前,JIT 关键的中间表示层(IR)优化工作几乎只依赖一两个人。为了改变这种状况,团队的目标是在 JIT 的前端、中端、后端都确保至少有两名活跃的维护者。

核心开发者 Brandt Bucher 率先行动,将庞大的优化任务拆解成一个一个具体的 “mega-issues”,例如“尝试优化某一条特定指令”。随后,另一位贡献者接手,开始将解释器的指令转换为对 JIT 更友好的形式,并为此编写了极其详细的操作指南。

结果如何?社区的热情被点燃了,先后有11位贡献者涌入并参与工作,几乎将整个解释器指令集都翻新了一遍。

社区协作期间 JIT 性能提升趋势图

图表显示了在社区集中优化期间,JIT相对于解释器的性能差异变化趋势。可以看到一个明确的、向上的优化轨迹。

性能从最初的1%提升逐渐来到了3-4%。这个数字看似微小,但它是一个强有力的证明:在结构清晰的指引下,社区协作的力量是真实且有效的。

戏剧性转折:一个“美丽的误会”成为关键突破

接下来的剧情发展,充满了戏剧性。

在一次剑桥的 CPython 核心开发者聚会上,Brandt Bucher 提出了一个大胆的建议:将 JIT 的前端从基于方法的编译(method-based)改为追踪模式(tracing)。另一位开发者最初持反对意见,但出于一种“友好的、赌气性质的开发心态”,他决定亲手重写一版追踪 JIT,目的竟然是为了证明这个想法行不通。

三天后,原型出炉了,结果慢得令人沮丧——比原来的版本还慢了6%。

就在大家几乎要放弃这个方向时,一个关键的“误解”发生了。 开发者 Mark Shannon 建议采用“双调度表”(dual dispatch table)的方案,让一个表专门存放“正常指令的追踪版本”。然而,负责实现的开发者理解错了,他实现了一个更为极端的方案:整个解释器中只保留一个专门负责追踪的指令,而第二张调度表里的所有入口都指向这唯一的指令。

令人惊讶的是,这个“错误”的方案居然奏效了!

原本设想的“双表”方案会导致解释器的代码体积几乎翻倍,代码膨胀带来的缓存不友好等问题反而可能拖慢速度。而这个“单指令,双表”的巧妙设计,仅仅增加了一个指令,就既保留了原始解释器的高速特性,又实现了关键的追踪记录功能。开发者们将其称为“真·双调度”,并戏称其为“一件小型的艺术品”。

这个架构上的巧思,让 JIT 的代码覆盖率瞬间提升了50%。 换句话说,如果没有当初那个美丽的“误解”,后续所有的优化努力,其效果可能都要大打折扣。

删代码的艺术:向“引用计数”开刀

另一个神来之笔是对“引用计数”的优化。

开发者 Matt Page 此前曾在字节码优化器里做过类似的工作。另一位贡献者注意到,在 JIT 生成的代码中,每一个减少引用计数的操作都附带了一个条件分支判断(用于检查对象是否应被释放)。他随手尝试了一下:“如果把这个分支判断删掉会怎样?”

结果令人震惊。 单看一个分支判断,其开销似乎微不足道。但在 Python 这样的语言中,几乎每条指令都可能涉及引用计数操作,海量的微小开销累积起来就变成了性能的“无底洞”。删除这些冗余分支带来了显著的性能收益。

更妙的是,这类优化工作特别适合新人练手。虽然这是一项需要耐心和细心的手动重构工作,但它能让新贡献者快速理解 CPython 解释器内存管理和 JIT 运作的核心机制。这项优化最终成为了 Python 3.15 JIT 的主要性能提升来源之一,真正做到了既提升性能,又培养社区人才,一箭双雕。

衣柜里的服务器与沉默的守护者

谈到支撑这一切的基础设施,故事又增添了一抹传奇色彩。开发者开玩笑地描述道:“我们的基础设施团队只有一个人,在 Savannah 的衣柜里跑了四台机器。”

象征性插图:衣柜中的服务器与怀旧科技感

Savannah Ostrowski 几乎是凭一己之力扛起了整个项目的持续集成(CI)和性能监控系统。每日自动运行的基准测试成了项目的“生命线”,任何微小的性能回退都能被立即捕捉到,每一次优化的效果也变得清晰可见。

Mark Shannon 被公认为技术核心,但用原作者的话说,“他已经在互联网上被夸得够多了,我就不再锦上添花了”。Diego Russo 则负责攻坚在 ARM 架构硬件上的 JIT 适配,以及更困难的性能剖析器集成工作,其难度“怎么强调都不为过”。而 Brandt Bucher 为机器码后端奠定的坚实基础至关重要,若非如此,新来的贡献者可能就得从手写汇编开始,那恐怕早就吓跑所有人了。

运气、人与持续不断的“耕耘”

项目主导者在总结时非常务实:运气很重要,人很重要,剩下的就是持续不断地“耕耘”。

他没有讲述一个孤胆英雄式的故事,而是坦诚地承认,成功源于“正确的时间、正确的地点、正确的人,以及一次正确的技术押注”。如果 Savannah、Mark、Diego、Brandt 这几位中的任何一位缺席,这个故事很可能就是另一个结局。

象征性插图:管道、齿轮与数据流,代表JIT编译过程

他也特别感谢了 PyPy 项目的 Carl Friedrich Bolz 等先驱,以及编译器领域的其他同行。“想法并非孤岛” —— 与编译器专家们的交流,阅读 PyPy 等先驱项目的源码,这些都让他成为了更优秀的 JIT 开发者。

截至目前,Python 3.15 的 JIT 在 macOS AArch64 平台上的性能已比纯解释器快 11-12%,在 x86_64 Linux 平台上则快 5-6%。虽然实现完全自由的多线程支持的目标被定在了 3.15/3.16 版本,但眼前的成果已足以让人振奋。

客观地说,11% 的性能提升在 JIT 编译器的历史长河中或许并不算里程碑式的突破。但考虑到他们是从“被资本抛弃、性能不如解释器”的深渊中起步的,这每一个百分点的提升都承载着非同寻常的重量。

有时候,阻碍技术前进的最大敌人并非其本身的复杂度,而是在困境中蔓延的绝望感。

他们用实际行动证明,即便在最艰难的时刻——缺乏资金、资源有限、代码甚至跑不过原始版本——只要团队不散,持续地分解问题、保持沟通、坚持编码,转机总会出现。

哪怕这个转机,最初是源于一次“美丽的误会”。这个故事本身,就是一次精彩的社区驱动的 开源实战。如果你对这类充满韧性与巧思的技术故事感兴趣,不妨来 云栈社区 的开发者广场逛逛,那里总有新鲜的见闻和观点在碰撞。

参考链接:
https://fidget-spinner.github.io/posts/jit-on-track.html




上一篇:MySQL删除数据后ibd文件不缩小?解析InnoDB空间回收机制
下一篇:Nvidia发布Vera Rubin七芯片平台,瞄准Agentic AI开启代际飞跃
您需要登录后才可以回帖 登录 | 立即注册

手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

GMT+8, 2026-3-19 10:04 , Processed in 0.471525 second(s), 41 queries , Gzip On.

Powered by Discuz! X3.5

© 2025-2026 云栈社区.

快速回复 返回顶部 返回列表