Ruby 编程语言的众多解释器和运行时
已发表: 2022-03-11介绍
就像 ruby gem 有很多不同的部分一样,Ruby 解释器也有多种实现。
最常用的 Ruby 解释器是参考实现 Ruby MRI,它由 Ruby 的创建者(Yukihiro Matsumoto)和 Ruby 核心团队用 C 语言开发。
我们的 Ruby on Rails 招聘指南提到 Rails 中的一些缺点可以通过使用替代的 Ruby 解释器来解决或避免。 本文展示了当今可用的各种现有 Ruby 解释器实现和运行时,并讨论了它们的优缺点。
Ruby 版本历史(以及它如何影响替代实现)
遗憾的是,Ruby 没有对应的 Python 语言参考(ISO/IEC 30170:2012 描述了 Ruby 1.8 / Ruby 1.9,但没有针对 Ruby 2.x 的相应规范)。 在没有任何此类语言规范的情况下,Ruby 实现者通常依赖于社区驱动的 RubySpec,该规范通过可以在任何 Ruby 解释器中运行的测试来指定 Ruby 语言的预期行为。 因此,Ruby 实现者使用 RubySpec 来验证他们的 Ruby 实现在行为上是否符合事实标准。
由于缺乏正式的规范,Ruby 的新版本通常简单地对应于 Ruby MRI 的新版本。 值得注意的是,有一个未解决的问题讨论了将 Ruby(语言)与 Ruby MRI 分离的设计过程。
然而,鉴于当前 Ruby 语言和 MRI 参考实现之间的紧密耦合,替代 Ruby 实现的开发人员有时很难跟上每个新 MRI 版本中引入的语言变化。
在 Ruby 1.8 和 Ruby 1.9 之间的转换中,从来没有比这更困难的了。 2007 年,为了清理和整合 Ruby 的语法(自从 Ruby 1.0 发布以来,这门语言已经发展了十年),Ruby 核心团队发布了 Ruby 1.9.0,该版本在该语言中引入了许多向后不兼容的问题. 因此,并不是所有的 Ruby 实现都投入了必要的努力来实现从 1.8 到 1.9 的语法跳跃。 因此,有几个基于 1.8 的 Ruby 实现不再被社区使用,但您仍然可以在网上找到或被老 Ruby 手谈论。
遵循语义版本控制原则,每年圣诞节都会发布一个新版本的 Ruby MRI。 Ruby 2.0(2013 年发布)和 2.1(2014 年发布)都引入了额外的语言特性,Ruby 开发人员可以利用这些特性,而不会失去与 Ruby 1.9 的向后兼容性。
为什么要使用替代的 Ruby 实现? 核磁共振有什么问题?
有多种替代 Ruby 实现,支持广泛的用例和环境。 Java 企业环境。 移动应用程序。 JavaScript 实现。 低 CPU/RAM 机器。 除了支持这些用例之外,替代实现有时还可以提供额外的速度提升或更有效的内存利用率,具体取决于应用程序的特性。
很长一段时间以来,许多 Ruby on Rails 开发人员使用 Ruby 企业版 (REE) 代替 MRI,与当时的 MRI 版本相比,利用了 REE 中更好的内存管理技术。 (REE 随后在 2012 年停产。)
虽然 MRI 是默认的 Ruby 实现,但它不一定是所有环境和场景的正确选择。 例如,MRI 的并发支持不如 JRuby 或 Rubinius。 此外,尽管 MRI 的内存和垃圾收集方案在不断改进,但它们仍然存在一些问题。
下面的 Ruby 实现调查旨在帮助您选择最适合您项目的操作目标和约束的解释器。
Matz 的 Ruby 解释器 (MRI) / CRuby
MRI 由 Yukihiro Matsumoto(“Matz”,Ruby 的创建者)领导的 Ruby 核心团队用 C 语言编写,是 Ruby 的参考实现,是事实上的标准。 例如,如果操作系统供应商将 Ruby 版本作为操作系统安装软件的一部分,则通常是 MRI 版本。 MRI 受益于比任何其他 Ruby 实现更多的付费核心团队成员,以及来自希望改进 Ruby 生态系统的个人或公司的专用资源。
每年圣诞节都会发布一个新版本的 Ruby MRI - 除了标准库更改之外,还经常实现新的语言功能。 功能首先在 Ruby MRI 中实现,通常基于 Ruby 核心开发人员邮件列表上的讨论。 其他 Ruby 实现滞后,在某些情况下甚至落后数年。
JRuby
JRuby 是在 Java 虚拟机 (JVM) 之上实现的 Ruby 版本。 随着 Java 以外的语言在 JVM 之上运行变得流行(我正在寻找你的方向,Clojure 和 Scala),基于 JVM 的 Ruby 实现可能会越来越流行。
JVM 中的 Ruby 还意味着 Ruby 可以在 Java 可以运行的任何地方运行(比如 Android 手机,例如使用 Ruboto)。 此外,由于 JVM 的互操作性,JRuby 代码可以利用 Java 平台,包括标准库和 3rd 方库。
JRuby 还可用于将基于 Rails 的解决方案引入纯 Java 部署环境,将 Rails 应用程序打包为.war
文件以部署到 Tomcat 容器,或作为 Java 小程序作为 Web 前端的一部分运行, 例如。
但是,对于那些不习惯 JVM 的人来说,JRuby 带来了与标准 JVM 相关的问题,例如 Ruby 解释器的启动缓慢、使用 3rd 方 Java 库时调试 CLASSPATH 问题、更大的内存使用以及现在您的代码需要在编写时考虑到线程安全注意事项。
此外,Ruby 的一些特性(C API,以及 Ruby 强大的自省工具之一,ObjectSpace 模块)在 JRuby 中没有实现。
综上所述,对于某些情况或项目,使用 JVM 的优势可能超过劣势。 JVM 允许许多性能优化,例如打开 JIT 编译器,或使用本机 Java 对象和 API。
作为一个引人注目的 JRuby 用例示例,我的一位前同事曾经遇到过一个 CPU 密集型问题,他最初使用 Ruby 1.9.3 中的线程解决了这个问题。 当他切换到 JRuby 并使用 Java 的java.util.concurrent.Executors
时,他看到此操作的性能提高了多个数量级(快了数万倍)。 在这里查看他的实验。
鲁比纽斯
Rubinius 是 Ruby 的一个实现,它在低级虚拟机 (LLVM) 之上实现了动态语言的通用运行时。 使用这种基础设施和 JIT 编译器技术,Rubinius 通常可以以比 MRI 更少的开销运行 Ruby 代码。
Rubinius 还使用尽可能多的 Ruby 构建,以使解释器/运行时的开发更快、更容易。

有趣的事实:RubySpec 最初是在实现 Rubinius 的过程中产生的。
与 JRuby 一样,Rubinius 包括一个 JIT 编译器、更好的内存管理和一个比 Ruby MRI 更成熟的虚拟机。 然而,与 JRuby 不同的是,Rubinius 支持 Ruby C 库,并且 Rubinius 的基础是用 C++ 编写的,而不是 Java。
当您需要 Rails 服务器上的高性能而又没有 JRuby 的学习曲线或其他缺点时,Rubinius 可能是一个很好的中间地带。
姆鲁比
mruby 被设计为 Ruby 的可嵌入版本(支持 Ruby 1.9.3)。 使用 mruby,您可以将 Ruby 作为原生应用程序中的脚本/自动化语言提供,将其用于游戏脚本,甚至用于对 Raspberry Pi 等微控制器板进行编程。
如果您的平台有严重的资源限制,mruby 可能只是适合您的 Ruby 解释器。 mruby 也被用于:
- 构建 iOS 应用程序(作为 RubyMotion 的竞争对手,如下所述)
- 将 Ruby 嵌入 iOS 应用程序,以提高开发速度
- 为最终用户提供用于自动化目的的嵌入式脚本语言
随着物联网越来越成为现实,家庭自动化逐渐成为现实,极其便携(且功能相对强大)的计算机变得越来越普遍,支持的目标平台环境也变得越来越多样化。 mruby 有助于使用与桌面相同的高效语言来实现这一点。
蛋白石
Opal 是将 Ruby 转换为 JavaScript 的转译器。
随着 Coffeescript 的兴起,开发人员了解到他们不必输入 JavaScript 来获取JavaScript。 虽然 Coffeescript 确实有它的优势,但使用它的时间足够长,你肯定会遇到你不喜欢该语言的事情。
输入 Opal:输入Ruby,获取 Javascript 。 很酷。
Opal 力求与其他 Ruby 实现尽可能一致,因此也针对 RubySpec 的一个子集进行了测试。 但是,由于 JavaScript 和 JavaScript 运行时的性质,确实存在一些不兼容性。 例如,Opal 中的字符串和符号是相等的,并且 Opal 不提供任何线程或 shell 执行机制。
Opal 独立运行或可用作 Rails 资产管道的一部分(例如,自动将somefile.js.rb
文件转换为 JavaScript)。
也许您有一个非常适合 JavaScript 的异步并发模式的问题域(例如小型 Node.js 服务),但想要该语言或来自 Ruby 空间的某些宝石。 在这种情况下,蛋白石可能是一个很好的解决方案。
或者您可能想编写一个完整的 Ruby Web 应用程序。 使用 Opal,您可以。 让一个 Ruby 解释器运行您的服务器端 Ruby 代码,然后让 Opal 生成 JavaScript 以在客户端运行。
Opal 认识到您可能会与其他 JavaScript API(例如 DOM 或 Node.js)进行交互。 因此,它可以很容易地过渡到 JavaScript,并在常见的 JavaScript 库(如 jQuery)上提供一些 Ruby 语法糖。
然而,Opal 以 JavaScript 为中心的特性既是它的优势,也是它的劣势。 不利的一面是,Opal 的运行时是 JavaScript 运行时,并且 Opal 受 JavaScript 设计决策的影响。 因此,如果您正在寻找一个好的 Ruby 实现来编写一个小的 shell 脚本,或者为您的 Rails 应用程序寻找一个更好的 Ruby 运行时,Opal 可能不是您的最佳选择。
RubyMotion
RubyMotion 既是 (a) 一个 Ruby 实现(使用 Objective-C 和 Cocoa 编写),又是 (b) 一组语言绑定,因此开发人员可以通过 Ruby 访问 Cocoa API。
RubyMotion 是一个商业产品,使您能够使用 Ruby 编写 Cocoa 原生应用程序。 RubyMotion 2.0 允许您使用 Ruby 编写 iOS 和 Mac OS X 应用程序,而 RubyMotion 3 承诺将为 Android 带来同样的支持。
RubyMotion 实现了 Ruby 语言的 1.9 版。
已失效的实现
自 Ruby 首次引入以来的这些年里,一些已经形成的 Ruby 实现已经被放弃或停止,例如:
- Ruby 企业版 (REE)。 REE 是来自 Phusion Passenger 的 MRI 1.8 的一个分支,它为 Web 开发人员实现了许多内存和垃圾收集改进。 几年来,它是为生产 Rails 站点部署的默认 Ruby 实现。 不过,它从未针对 Ruby 1.9 或 Ruby 2.0 进行更新,并最终在 2012 年停产。
- 铁红宝石。 IronRuby 是在 Microsoft .NET 之上实现的 Ruby,用 C# 编写,该项目有一段时间是由 Microsoft 资助的。 IronRuby 于 2011 年被放弃,最后一次支持 Ruby 1.8.6。
包起来
Ruby 环境中有各种各样的运行时和解释器可供选择。 对于大多数 Ruby 项目,Ruby 参考实现 (Ruby MRI) 仍然是首选的解释器。 但是,根据您的功能和技术目标和限制,替代 Ruby 实现很可能是您项目的正确选择。
作为 Ruby 的参考实现,MRI 更快地获得了新的语言特性,具有足够好的并发性和内存故事(只会越来越好),并且与 gem 具有最广泛的兼容性(一些部分是用 C 编写的)。 总而言之,MRI 是通用 Ruby 代码的可靠选择。
对于更大的企业部署,或者需要与 Java 代码(或其他 JVM 语言)交互或需要高度发展的并发模式的情况,JRuby 是一个令人信服的选择。
当然,如果您有独特的需求(例如,编写 JavaScript、在当前一代的嵌入式设备上运行等等),其他 Ruby 替代品可能正是您正在寻找的。
Ruby 有各种各样的运行时和解释器可供选择,Ruby 表明自己是一种灵活的语言,适用于各种计算环境,从企业大型 Java 部署商店到控制办公室红绿灯的软件你上周末把你的树莓派挂了。 为正确的目的选择正确的工具是必不可少的,是的,但希望本文向您展示了 Ruby 远不止是您的操作系统附带的默认 Ruby 解释器。
随着对语言的更改提出来,Ruby 的世界通过与核心 Ruby MRI 团队合作的替代 Ruby 实现团队大大增强。 他们为 Ruby 实现社区增加了多样性,增加了他们来之不易的 Ruby 实现经验以及他们对语言特性的看法。 Ruby 爱好者共同对这些团队表示感谢。 为他们的努力点赞!