使用正确的 Ruby 解释器来运行程序可以发挥重要作用,不幸的是很难找到关于不同 Ruby 解释器选择的文章,或者如何选择正确的解释器。
下面我们在 Ruby 中汇编了大量有关解释器的内容,即使你在这篇文章开始时问到 “什么是Ruby解释器?”,您仍将准确了解做出正确决策所需的知识。
什么是解释器? 编译和解释编程语言
语言是沟通的基础,它们由一组标准的词汇、语法和语法组成,两人同意交换信息。但是,当两个人不说同一种语言时,您需要一种方法将相同的想法从一种语言翻译或解释成另外一种。
翻译和解释的概念也同样适用于编程,机器无法自己理解人类编程产出的的高级代码,它们只能执行机器码,这是计算机 CPU 可以立即理解的一组有限的低级指令。
机器有两种运行编程语言的方法,比如 Ruby:编译和解释。
编译型语言需要一个称为编译器的工具,在用户运行程序之前,编译器必须将高级代码转换为一系列低级指令,此机器代码特定于运行程序的机器。
解释型编程语言需要一个称为解释器的工具,在程序运行时,解释器逐行将源代码转换为机器代码。
这种差异就像翻译和口译外语之间的区别,翻译人员会在需要翻译人员使用之前提前完成工作。口译员现场进行翻译,而需要的人现场倾听。
编译型语言和解释型语言都有其优点和缺点,某些语言(如 Java)使用两种方法混合。通常解释型语言更灵活,对不同系统更具可移植性,并且更易于调试。但他们通过牺牲速度和性能来为这些优势付出代价。
编译型语言通常比解释语言更快,这是因为编译器有时间优化运行程序的特定机器的代码。
虽然 Ruby 经常被解释,但它其实也可以根据语言实现进行解释和编译,在本文的其余部分,我们将仅讨论 Ruby 的解释器。
什么是 Ruby 解释器?
Ruby 解释器是能够解释用 Ruby 语言编写的源代码的程序。
就像可以让不同的人来翻译或口译一样,这不是一个单一版本的 Ruby 解释器。相反,Ruby 开发人员有多个解释器选择。每个版本赋予语言略有不同的 “味道”。
那么你怎么能确定你使用的解释器实际上运行的是 “真正的” Ruby?通过使用 Ruby Spec Suite (也称为 ruby/spec),Ruby Spec Suite 是一组测试,用于在解释程序时验证给定的 Ruby 实现是否具有正确的行为和结果。
Ruby 解释器选择:YARV, Ruby MRI, JRuby, and Rubinius
下面,我们将讨论 Ruby 解释器最流行的替代方案:YARV,Ruby MRI / CRuby,JRuby 和 Rubinius,下面的所有解释器都通过了 Ruby Spec Suite,是运行 Ruby 代码的可靠、成熟的选择。
YARV
YARV (Yet Another Ruby VM) 是基于堆栈的解释器技术,为 Ruby 的官方解释器提供支持。从Ruby 1.9 版开始,YARV 取代了旧版本的 Ruby MRI(也称为 CRuby);从 Ruby 2.6 开始,YARV 即是 Ruby 的官方解释器。
当您运行 Ruby 程序时,YARV 会将代码转换为可在 Ruby 虚拟机(VM)中运行的有限指令集。 VM 是在您的计算机上运行的程序,它模拟独立的计算机以具有更好的可预测性和稳定性。这可确保所有计算机都可以运行 Ruby,无论他们使用哪种特定的机器码。
Ruby MRI/CRuby
在 YARV 版本在 Ruby 1.9 之前,默认的 Ruby 解释器是 Ruby MRI,也称为 CRuby。 Ruby MRI 代表着 Matz 的 Ruby Interpreter(以“Matz”命名,或者是 Ruby 的首席设计师 Yukihiro Matsumoto 松本行弘)。
替代名称 CRuby 反映了解释器采用 C 编程语言的事实。 CRuby 与 YARV 的不同之处在于:YARV 使用堆栈来解析 Ruby 代码,而 CRuby 使用抽象语法树。
JRuby
正如 CRuby 在 C 语言中一样,JRuby 是 Java 编程语言中的 Ruby 解释器。 JRuby 遵循其他在 Java 虚拟机(JVM)上运行的编程语言的脚步,例如 Clojure 和 Scala。
因为 JRuby 使用 JVM,所以您可以在任何可以运行 Java 程序的地方运行 Ruby 程序,从笔记本电脑到 Android 手机。 JRuby 还可以利用 Java 标准和三方库。
Rubinius
Rubinius 试图将 Ruby 程序解释为尽可能少的 C 代码,区别于 Ruby MRI / CRuby。 Rubinius 的基础是 C++,而其他部分使用尽可能多的 Ruby 代码。
Rubinius 包含一个 “Just In Time”(JIT)编译器,它在程序运行时编译代码,帮助它更加动态地运行,这使其在内存管理和速度方面比 Ruby MRI 有所改进。
你应该使用哪个 Ruby 解释器?
Ruby 解释器使用是一个开放式问题,取决于你的具体情况。
如果您已经安装了 Ruby 的默认版本,那么您几乎肯定会使用 YARV(如果是 Ruby 1.9 及更高版本)或 Ruby MRI(如果是Ruby 1.8 及更低版本)。在许多情况下,这个默认选择足以满足 Ruby 开发人员的需求。
但是,如果您的 Ruby 程序具有高性能要求,Rubinius 或 JRuby 可能会更好。根据一项基准测试,Rubinius 和 JRuby 的性能大约是 Ruby MRI 的两倍。
Ruby 解释器使用的另一个考虑因素是线程和并行性问题。 Ruby MRI 使用称为全局解释器锁(GIL)。 GIL 可防止多个程序线程同时访问相同的数据。默认情况下,Ruby 是单线程的,不允许并行和多线程。
但是,这种限制在 Ruby 解释器的其他实现中不存在,例如 Rubinius 和 JRuby,你可以充分利用多核和多 CPU 系统,显着提升性能。
好消息是,Ruby 团队希望通过一种称为 Guilds 的机制在即将发布的 Ruby 3 版本中绕过GIL的限制。将来你可能会在默认版本的 Ruby 中看到并行和多线程的一些变好的情况。但你必须耐心等待 Ruby 3(目前没有明确发布日期)。
最后
上面列出的替代方案绝不是 Ruby 实现的唯一选择。 mruby 是一个 Ruby 实现,适用于 Raspberry Pi 等嵌入式系统。同时 Opal 是一个将 Ruby 转换为 JavaScript 的编译器。
但是,对于大多数 Ruby 场景,选择以下这些不会错:
默认的 Ruby 实现,YARV 或 Ruby MRI,可能适合许多 Ruby 程序员的需求。它以最快的迭代新的 Ruby 语言功能,并且与不同的 Ruby gems 具有最大的兼容性。但是,它目前缺乏真正的并行,并且速度可能比其他解释器慢。
当你需要在许多不同的系统(包括企业计算机)上运行 Ruby 时,JRuby 是一个很好的选择。 JRuby 还可以轻松地与 Java 代码进行交互。
当需要性能非常高,或者想要使用并行性时,Rubinius 是一个很好的选择。它还使您能够使用 C 或 C++ 中的代码连接 Ruby。