Ruby 2.6.0 正式版已经发布,引入了许多新功能和性能改进,最值得关注的有亮点:

  • 新的 JIT 编译器
  • RubyVM::AbstractSyntaxTree 模块

JIT [实验]

Ruby 2.6 引入了 JIT (Just-in-time) 编译器实现。

JIT 编译器旨在提高 Ruby 性能。与其他语言的普通 JIT 编译器不同,Ruby 的 JIT 编译器以一种独特的方式进行 JIT 编译,它先将 Ruby 编译成 C 代码,然后通过生成通用的 C 编译器过程 (compiler process) 来生成原生机器码。详情可查阅 Vladimir Makarov 的 MJIT 组织

要启用 JIT 编译器,在命令行或 $RUBYOPT 环境变量中指定 --jit 参数即可。

在一个名叫 Optcarrot 的 CPU 密集计算基准测试中,Ruby 2.6 与 Ruby 2.5 相比,性能提高了 1.7 倍。不过目前仍然处于试验阶段,详见 Ruby 2.6 JIT - 进程与未来

请保持对 Ruby 新时代性能的关注。

RubyVM::AbstractSyntaxTree [实验]

Ruby 2.6 引入了 RubyVM::AbstractSyntaxTree 模块,此模块向后兼容性不做保证。
**
此模块提供一个 parse 方法,传入 Ruby 代码字符串,返回 AST(抽象语法树)节点。而 parse_file 方法则接受一个 Ruby 代码文件作为参数,返回 AST 节点。

同时引入了 RubyVM::AbstractSyntaxTree::Node 类,你可以从 Node 对象中获取位置信息和子节点。此功能尚处于实验性质。

其它新特性

  • Kernel#yield_self 添加新别名 then[Feature #14594]
  • 常量名现在可以以非 ASCII 大写字母开头。[Feature #13770]
  • 无限范围 [Feature #12912]
    引入了无限范围 (1..)。这个范围没有终点,以下是使用场景的举例。
  1. ary[1..] # 等价于 ary[1..-1] 而不需要魔法 -1
  2. (1..).each {|index| ... } # 从 1 开始无限循环
  3. ary.zip(1..) {|elem, index| ... } # ary.each.with_index(1) { ... }
  • 新增 Enumerable#chainEnumerator#+ [Feature #15144]
  • ProcMethod 新增了函数构造操作符 <<>> [Feature #6284]
  1. f = proc{|x| x + 2}
  2. g = proc{|x| x * 3}
  3. (f << g).call(3) # -> 11; identical to f(g(3))
  4. (f >> g).call(3) # -> 15; identical to g(f(3))
  • 新增 Binding#source_location[Feature #14230]
  • 此方法以一个二元组数组 __FILE____LINE__ 的形式返回 binding 的源代码路径。传统上,这可以通过执行 eval("[__FILE__, __LINE__]", binding) 来获得相同的数据。但我们计划改变这一行为让 Kernel#eval 忽略 binding 的源代码路径 [Bug #4352]。所以,用户需要通过新加入的方法来替代之前的 Kernel#eval
  • 增加 :exception 选项,以让 Kernel.#system 抛出错误而不是返回 false[Feature #14386]
  • 新增 oneshot 模式 [Feature #15022]
    • 此模式检查「每一行代码是否都至少被执行一次」,而不是「每行代码被执行了几次」。每行代码的 hook 至多被调用一次,并会在调用后将 hook 标识移除。换句话说,移除后的代码运行将没有额外的性能开销。
    • Coverage.start 方法新增 :oneshot_lines 关键字参数。
    • Coverage.result 方法新增 :stop:clear 关键字参数。如果 clear 被设置为 true,它会清空计数器。如果 stop 被设置为 true,它会禁用覆盖测量。
    • 新增 Coverage.line_stub,其为从源代码新建代码覆盖存根(stub)提供了一个简单的帮助函数。
  • FileUtils#cp_lr[Feature #4189]

性能提升

  • 由于移除了对 $SAFE 临时赋值的支持,提升 Proc#call 的速度。[Feature #14318]

通过 lc_fizzbuzz 多次使用 Proc#call 的 benchmark 我们测量到了 1.4 倍性能提升 [Bug #10212]

  • 提升了当 block 是代码块参数时 block.call 的性能。[Feature #14330]

通过与 Ruby 2.5 中引入的提升代码块传递的性能的方法结合,Ruby 2.6 进一步提升了传递代码块调用时的性能。通过 micro-benchmark 测试有 2.6 倍性能提升。[Feature #14045]

  • 引入了瞬态堆 (theap)。 [Bug #14858] [Feature #14989]

瞬态堆是用于管理指向特定类(Array、Hash、Object 和 Struct)短生命周期内存对象的堆。例如,创建小而短生命周期的哈希对象的速度提升到了 2 倍快。根据 rdoc benchmark,我们观察到了 6% 到 7% 的性能提升。

  • 协程采用了原生实现(arm32arm64ppc64lewin32win64x86amd64)显著提升了 Fiber 的性能。 [Feature #14739]

Fiber.yieldFiber#resume 方法在 64 位 Linux 上提升了 5 倍性能。对于使用 Fiber 密集的程序,约有最高 5% 的性能提升。

其它自 2.5 以来值得注意的新特性

  • $SAFE 成为了进程全局状态,我们可以再次将其设为 0[Feature #14250]
  • 不再建议将 safe_level 参数传递给 ERB.new 的行为。trim_modeeoutvar 参数被转换成了关键词参数。[Feature #14256]
  • 升级支持的 Unicode 版本至 11。我们计划在未来 Ruby 2.6 的小更新中升级至 12 和 12.1。其将引入新的日本年号
  • 合并 RubyGems 3.0.1,--ri--rdoc 选项已被移除。请使用 --document--no-document 选项来替代他们。
  • 合并 Bundler 作为默认 gem 安装。
  • 不含 rescueelse 现在会引起语法错误。[实验性][Feature #14606]

更多详情见 NEWS提交日志 以查看详情。

随着这些变动,自 Ruby 2.5.0 已发生了 6437 个文件变更,231471 行新增(+),98498 行删除(-)

圣诞快乐!享受你 Ruby 2.6 的编程之旅吧!

原文连接:https://www.ruby-lang.org/en/news/2018/12/25/ruby-2-6-0-released/