Ruby 3.0.0 发布
由 naruse 发布于 2020 年 12 月 25 日
我们很高兴地宣布 Ruby 3.0.0 的发布。自 2015 年以来,我们一直在为 Ruby 3 的目标——性能、并发和类型——进行不懈的努力。特别是在性能方面,Matz 表示“Ruby3 将比 Ruby2 快 3 倍”,又称 Ruby 3x3。

通过 Optcarrot 基准测试,该测试基于 NES 游戏模拟工作负载衡量单线程性能,其性能比 Ruby 2.0 快了 3 倍!
Ruby 3.0.0 通过以下方式实现了这些目标:
- 性能
- MJIT
- 并发
- Ractor
- Fiber 调度器
- 类型(静态分析)
- RBS
- TypeProf
凭借上述性能提升,Ruby 3.0 引入了以下几项新功能。
性能
当我首次在会议主题演讲中宣布“Ruby3x3”时,许多人,包括核心团队成员,都觉得“Matz 在吹牛”。事实上,我自己也有这种感觉。但我们做到了。我很荣幸看到核心团队确实实现了将 Ruby 3.0 的性能提升到 Ruby 2.0 的三倍(在某些基准测试中)。– Matz
MJIT
MJIT 进行了多项改进。详情请参阅 NEWS。
从 Ruby 3.0 开始,JIT 预计将在有限的工作负载中提供性能改进,例如游戏(Optcarrot)、AI(Rubykon),或任何大部分时间都在反复调用少量方法来完成的应用程序。
尽管 Ruby 3.0 显著减小了 JIT 代码的大小,但对于 Rails 这样经常在大量方法之间切换而导致 JIT 加剧的 i-cache 缺失的工作负载,它仍然尚未做好优化准备。敬请关注 Ruby 3.1 以获得进一步的改进。
并发 / 并行
如今已是多核时代。并发性非常重要。通过 Ractor 和 Async Fiber,Ruby 将成为一门真正的并发语言。— Matz
Ractor(实验性)
Ractor 是一种类似 Actor 模型并发抽象,旨在提供并行执行功能,而无需担心线程安全。
您可以创建多个 Ractor 并并行运行它们。Ractor 使您能够创建线程安全的并行程序,因为 Ractor 无法共享普通对象。Ractor 之间的通信通过消息传递来支持。
为了限制对象的共享,Ractor 对 Ruby 的语法进行了一些限制(如果没有多个 Ractor,则没有限制)。
规范和实现尚未成熟,未来可能会发生变化,因此此功能被标记为实验性,并在第一次 Ractor.new 出现时显示“experimental feature”警告。
以下小程序通过顺序执行 4 次或使用 Ractor 并行执行 4 次来测量著名基准测试 tak 函数(Tak (function) - Wikipedia)的执行时间。
def tarai(x, y, z) =
x <= y ? y : tarai(tarai(x-1, y, z),
tarai(y-1, z, x),
tarai(z-1, x, y))
require 'benchmark'
Benchmark.bm do |x|
# sequential version
x.report('seq'){ 4.times{ tarai(14, 7, 0) } }
# parallel version
x.report('par'){
4.times.map do
Ractor.new { tarai(14, 7, 0) }
end.each(&:take)
}
end
Benchmark result:
user system total real
seq 64.560736 0.001101 64.561837 ( 64.562194)
par 66.422010 0.015999 66.438009 ( 16.685797)
结果是在 Ubuntu 20.04, Intel(R) Core(TM) i7-6700 (4 核, 8 线程) 上测得的。结果表明,并行版本比顺序版本快 3.87 倍。
有关更多详细信息,请参阅 doc/ractor.md。
Fiber 调度器
Fiber#scheduler 被引入,用于拦截阻塞操作。这使得轻量级并发成为可能,而无需更改现有代码。观看 “Don’t Wait For Me, Scalable Concurrency for Ruby 3” 来了解其工作原理的概述。
当前支持的类/方法
Mutex#lock,Mutex#unlock,Mutex#sleepConditionVariable#waitQueue#pop,SizedQueue#pushThread#joinKernel#sleepProcess.waitIO#wait,IO#read,IO#write和相关方法(例如#wait_readable,#gets,#puts等)。IO#select**不支持**。
此示例程序将并发执行多个 HTTP 请求
require 'async'
require 'net/http'
require 'uri'
Async do
["ruby", "rails", "async"].each do |topic|
Async do
Net::HTTP.get(URI "https://www.google.com/search?q=#{topic}")
end
end
end
它使用了 async,它提供了事件循环。此事件循环使用 Fiber#scheduler 钩子使 Net::HTTP 变为非阻塞。其他 gem 可以使用此接口为 Ruby 提供非阻塞执行,并且这些 gem 可以与其他 Ruby 实现(例如 JRuby, TruffleRuby)兼容,因为它们也支持相同的非阻塞钩子。
静态分析
2010 年代是静态类型编程语言的时代。Ruby 通过抽象解释,在不进行类型声明的情况下,以静态类型检查来寻求未来。RBS 和 TypeProf 是迈向未来的第一步。未来还有更多步骤。— Matz
RBS
RBS 是一种描述 Ruby 程序类型的语言。
包括 TypeProf 在内的类型检查器以及其他支持 RBS 的工具将通过 RBS 定义更好地理解 Ruby 程序。
您可以写下类和模块的定义:类中定义的方法、实例变量及其类型,以及继承/混入关系。
RBS 的目标是支持 Ruby 程序中常见的模式,它允许编写高级类型,包括联合类型、方法重载和泛型。它还支持具有*接口类型*的鸭子类型。
Ruby 3.0 附带了 rbs gem,它允许解析和处理用 RBS 编写的类型定义。以下是一个包含类、模块和常量定义的 RBS 小示例。
module ChatApp
VERSION: String
class Channel
attr_reader name: String
attr_reader messages: Array[Message]
attr_reader users: Array[User | Bot] # `|` means union types, `User` or `Bot`.
def initialize: (String) -> void
def post: (String, from: User | Bot) -> Message # Method overloading is supported.
| (File, from: User | Bot) -> Message
end
end
有关更多详细信息,请参阅 rbs gem 的 README。
TypeProf
TypeProf 是 Ruby 包中捆绑的类型分析工具。
目前,TypeProf 充当一种类型推断工具。
它读取纯(非类型注解)Ruby 代码,分析定义了哪些方法以及如何使用它们,并生成 RBS 格式的类型签名原型。
这里有一个 TypeProf 的简单演示。
一个输入示例
# test.rb
class User
def initialize(name:, age:)
@name, @age = name, age
end
attr_reader :name, :age
end
User.new(name: "John", age: 20)
一个输出示例
$ typeprof test.rb
# Classes
class User
attr_reader name : String
attr_reader age : Integer
def initialize : (name: String, age: Integer) -> [String, Integer]
end
您可以将输入保存为“test.rb”并调用命令“typeprof test.rb”来运行 TypeProf。
您还可以 在线尝试 TypeProf。(它在服务器端运行 TypeProf,如果失效,敬请谅解!)
有关详细信息,请参阅 TypeProf 文档和 演示。
TypeProf 仍处于实验阶段,尚未成熟;目前仅支持 Ruby 语言的子集,类型错误检测也有限。但它仍在快速发展,以提高语言特性覆盖率、分析性能和可用性。欢迎任何反馈。
其他值得注意的新特性
-
一行模式匹配已重新设计。(实验性)
-
添加了
=>。它可以像右侧赋值一样使用。0 => a p a #=> 0 {b: 0, c: 1} => {b:} p b #=> 0 -
in的返回值现已更改为true或false。# version 3.0 0 in 1 #=> false # version 2.7 0 in 1 #=> raise NoMatchingPatternError
-
-
添加了查找模式。(实验性)
case ["a", 1, "b", "c", 2, "d", "e", "f", 3] in [*pre, String => x, String => y, *post] p pre #=> ["a", 1] p x #=> "b" p y #=> "c" p post #=> [2, "d", "e", "f", 3] end -
添加了无尽方法定义。
def square(x) = x * x -
Hash#except现在是内置的。h = { a: 1, b: 2, c: 3 } p h.except(:a) #=> {:b=>2, :c=>3} -
添加了内存视图作为一项实验性功能。
- 这是一套新的 C API,用于在扩展库之间交换原始内存区域,例如数字数组或位图图像。扩展库还可以共享由形状、元素格式等组成的内存区域的元数据。利用这些类型的元数据,扩展库甚至可以适当地共享多维数组。此功能的设计参考了 Python 的缓冲区协议。
性能改进
- 在 IRB 中粘贴长代码比 Ruby 2.7.0 附带的版本快 53 倍。例如,粘贴 此示例代码所需的时间从 11.7 秒减少到 0.22 秒。
-
IRB 中已添加
measure命令。它允许进行简单的执行时间测量。irb(main):001:0> 3 => 3 irb(main):002:0> measure TIME is added. => nil irb(main):003:0> 3 processing time: 0.000058s => 3 irb(main):004:0> measure :off => nil irb(main):005:0> 3 => 3
自 2.7 以来的其他重要更改
- 关键字参数已从其他参数中分离。
- 原则上,在 Ruby 2.7 中会发出警告的代码将不再工作。详情请参阅 本文档。
-
顺便说一句,参数转发现在支持前置参数。
def method_missing(meth, ...) send(:"do_#{ meth }", ...) end
- 模式匹配(
case/in)不再是实验性的。- 有关详细信息,请参阅 模式匹配文档。
- $SAFE 功能已完全移除;现在它是一个普通的全局变量。
- Ruby 2.5 中已反转了后向追溯的顺序;此更改已被恢复。现在后向追溯的行为与 Ruby 2.4 相同:先打印错误消息和异常发生的行号,然后打印其调用者。
- 一些标准库已更新。
- RubyGems 3.2.3
- Bundler 2.2.3
- IRB 1.3.0
- Reline 0.2.0
- Psych 3.3.0
- JSON 2.5.1
- BigDecimal 3.0.0
- CSV 3.1.9
- Date 3.1.0
- Digest 3.0.0
- Fiddle 1.0.6
- StringIO 3.0.0
- StringScanner 3.0.0
- 等。
- 以下库不再是捆绑的 gem 或标准库。安装相应的 gem 以使用这些功能。
- sdbm
- webrick
- net-telnet
- xmlrpc
- 以下默认 gems 现在是打包 gems。
- rexml
- rss
- 以下 stdlib 文件现在是默认 gem,并在 rubygems.org 上发布。
- English
- abbrev
- base64
- drb
- debug
- erb
- find
- net-ftp
- net-http
- net-imap
- net-protocol
- open-uri
- optparse
- pp
- prettyprint
- resolv-replace
- resolv
- rinda
- set
- securerandom
- shellwords
- tempfile
- tmpdir
- time
- tsort
- un
- weakref
- digest
- io-nonblock
- io-wait
- nkf
- pathname
- syslog
- win32ole
有关更多详细信息,请参阅 NEWS 或 commit 日志。
通过这些更改,自 Ruby 2.7.0 以来,4028 个文件已更改,200058 行插入(+),154063 行删除(-)!
Ruby 3.0 是一个里程碑。语言在不断发展,同时保持兼容性。但这并非终点。Ruby 将继续进步,变得更加伟大。敬请关注!— Matz
圣诞快乐,节日快乐,祝您使用 Ruby 3.0 编程愉快!
下载
-
https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.tar.gz
SIZE: 19539509 SHA1: 233873708c1ce9fdc295e0ef1c25e64f9b98b062 SHA256: a13ed141a1c18eb967aac1e33f4d6ad5f21be1ac543c344e0d6feeee54af8e28 SHA512: e62f4f63dc12cff424e8a09adc06477e1fa1ee2a9b2b6e28ca22fd52a211e8b8891c0045d47935014a83f2df2d6fc7c8a4fd87f01e63c585afc5ef753e1dd1c1 -
https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.tar.xz
SIZE: 14374176 SHA1: c142899d70a1326c5a71311b17168f98c15e5d89 SHA256: 68bfaeef027b6ccd0032504a68ae69721a70e97d921ff328c0c8836c798f6cb1 SHA512: 2a23c2894e62e24bb20cec6b2a016b66d7df05083668726b6f70af8338211cfec417aa3624290d1f5ccd130f65ee7b52b5db7d428abc4a9460459c9a5dd1a450 -
https://cache.ruby-lang.org/pub/ruby/3.0/ruby-3.0.0.zip
SIZE: 23862057 SHA1: 2a9629102d71c7fe7f31a8c91f64e570a40d093c SHA256: a5e4fa7dc5434a7259e9a29527eeea2c99eeb5e82708f66bb07731233bc860f4 SHA512: e5bf742309d79f05ec1bd1861106f4b103e4819ca2b92a826423ff451465b49573a917cb893d43a98852435966323e2820a4b9f9377f36cf771b8c658f80fa5b
什么是 Ruby
Ruby 最初由 Matz(Yukihiro Matsumoto)于 1993 年开发,现已作为开源项目进行开发。它运行在多个平台上,并在全世界范围内得到广泛应用,尤其是在 Web 开发领域。
近期新闻
Ruby 4.0.0 发布
我们很高兴地宣布 Ruby 4.0.0 的发布。Ruby 4.0 引入了“Ruby Box”和“ZJIT”,并增加了许多改进。
由 naruse 发布于 2025 年 12 月 25 日
Ruby 文档的全新外观
继 ruby-lang.org 重新设计之后,我们还有更多好消息来庆祝 Ruby 成立 30 周年:docs.ruby-lang.org 采用了 Aliki——RDoc 的新默认主题,焕然一新。
由 Stan Lo 发布于 2025 年 12 月 23 日
重新设计我们的网站标识
我们很高兴地宣布对我们的网站进行全面重新设计。此次更新的设计由 Akatsuka Taeko 创作。
由 Hiroshi SHIBATA 发布于 2025 年 12 月 22 日
Ruby 4.0.0 preview3 发布
我们很高兴地宣布 Ruby 4.0.0-preview3 的发布。Ruby 4.0 引入了 Ruby::Box 和“ZJIT”,并增加了许多改进。
由 naruse 发布于 2025 年 12 月 18 日