Ruby 3.1.0加入程序内JIT编译器YJIT,有效加速Rails应用程序性能

Ruby在圣诞节当天,发布了最新的Ruby 3.1.0,这个版本加入新的实验性程序内JIT编译器YJIT,能进一步提升许多真实使用案例的性能,在测试工具railsbench和样板语言liquid-render上的执行速度都非常亮眼,另外,Ruby 3.1.0还加入新的调试器来提升调试性能。

Ruby 3.1.0所加入的这个YJIT,是由Shopify开发的程序内编译器。在2018年的时候,Ruby 2.6加入了MJIT(Method-based JIT),来提升程序性能,而在去年圣诞节,Ruby开发团队也赶在圣诞节,希望给社群一个圣诞节礼物,宣布实现Ruby3x3,Ruby3x3是由Ruby主要设计人松本行弘(Yukihiro Matsumoto,Matz),对开发团队设下的目标,希望Ruby 3的速度可以是Ruby 2的3倍。

开发团队以Ruby 2.0、Ruby 3.0以及Ruby 3.0 JIT来测试Optcarrot基准测试,而结果也显示Ruby 3.0 JIT的单线程性能是Ruby 2.0的3倍,但开发人员通常不会在生产环境中激活MJIT,官方也提到,尽管Optcarrot基准测试表现让人印象深刻,但终究并没有让现实世界的业务受益。

而最近Shopify贡献了许多Ruby的更新,来改善他们自家的Rails应用程序,而YJIT便是其中一个重要的贡献,目的是要提高Rails应用程序的性能。MJIT的问题在于,应用程序存在大量方法时,使用JIT反而会使执行速度变慢,JIT仅可以提升游戏、人工智能或是调用少量方法的工作负载性能。原因是,MJIT并没有针对Rails等,需要大量调用方法的工作负载进行优化,反而会加重这类工作指令缓存(i-cache)丢失的问题,而官方也一直未能解决这个问题。

不同于MJIT是个基于方法的JIT编译器,并且使用外部C编译器,YJIT使用基本区块控制(Basic Block Versioning),并将JIT编译器包含在其中。由Shopify成员发布,在2021年10月19日所公开的论文,详细介绍了YJIT这个新方法,这是一个以LBBV(Lazy Basic Block Versioning)架构为基础,在CRuby内部构建新的JIT编译器的方法,论文提到,虽然这个编译器比不上TruffleRuby的高峰性能,但是提供与现有Ruby程序代码接近100%的兼容性,而且具有超高速预热特性,在实际软件的大型基准测试,提供15%到19%的加速。

独立重新实例Ruby语言,像是JRuby和TruffleRuby,虽然能够大幅提升性能,但是在支持语言新功能上,往往落后CRuby,因此限制这些语言的实际应用。YJIT则是一个更通用的Ruby性能解决方案,在兼容大部分现有Ruby程序代码的前提,大幅提升程序代码性能。

在实际的软件中,YJIT实现了快速预热和性能改进的目标,在railsbench速度提升达22%,而liquid-render则有39%。不过目前YJIT仍是一项实验性功能,在默认情况下停用,开发者可以在类Unix x86-64平台上手动打开。

除了YJIT,Ruby 3.1.0另一项值得关注的更新,是捆绑了一个完全重写的调试器debug.gem,这个新的调试器大幅改善调试性能,现在即便使用调试器,也不会减慢应用程序的速度,同时支持远程调试,支持VS Code和Chrome浏览器等更多调试前端,并且加入多程序和多线程调试等功能。

Ruby过去捆绑了lib/debug.rb调试器,但是并没有得到妥善的维护,在性能和功能上都存在一些问题,而现在debug.gem则完全取代lib/debug.rb。

IRB(Interactive Ruby)交互式命令行工具,现在添加自动完成功能,开发者只需要在其中输入程序代码,便会出现完成候选对话框,而且当开发者安装了相关文件,在选择候选选项时,对话框旁还会出现文件对话框,显示部分内容。