NEWS for Ruby 3.3.0
本文档列出了自 3.2.0 版本以来用户可见的功能更改,不包括 bug 修复。
请注意,每个条目都保持得尽可能简洁,详情请参阅链接。
命令行选项
-
引入了一个新的
performance警告类别。默认情况下,即使在详细模式下也不会显示它们。使用-W:performance或Warning[:performance] = true来启用它们。[Feature #19538] -
引入了一个新的
RUBY_CRASH_REPORT环境变量,允许将 Ruby 崩溃报告重定向到文件或子命令。有关更多详细信息,请参阅 ruby 手册页的BUG REPORT ENVIRONMENT部分。[Feature #19790]
核心类更新
注意:此处仅列出重要的类更新。
-
-
Array#pack现在对未知指令会引发ArgumentError。[Bug #19150]
-
-
-
添加了
Dir.for_fd,用于返回一个Dir对象,该对象对应于由提供的目录文件描述符指定的目录。[Feature #19347] -
添加了
Dir.fchdir,用于将当前目录更改为由提供的目录文件描述符指定的目录。[Feature #19347] -
添加了
Dir#chdir,用于将当前目录更改为由提供的Dir对象指定的目录。[Feature #19347]
-
-
-
已移除
Encoding#replicate,它已被弃用。[Feature #18949]
-
-
-
引入
Fiber#kill。[Bug #595]fiber = Fiber.new do while true puts "Yielding..." Fiber.yield end ensure puts "Exiting..." end fiber.resume # Yielding... fiber.kill # Exiting...
-
-
-
MatchData#named_captures现在接受可选的symbolize_names关键字参数。[Feature #19591]
-
-
Module
-
添加了
Module#set_temporary_name,用于为模块设置临时名称。[Feature #19521]
-
-
-
新的核心类,用于构建带有弱引用的集合。该类使用相等性语义来查找键,就像常规哈希一样,但它不持有键的强引用。[Feature #18498]
-
-
-
添加了
ObjectSpace::WeakMap#delete,用于立即清除弱映射条目。[Feature #19561]
-
-
-
现在
Proc#dup和Proc#clone分别调用 initialize_dup 和 initialize_clone 钩子。[Feature #19362]
-
-
Process
-
新的
Process.warmup方法,它通知 Ruby 虚拟机启动序列已完成,现在是优化应用程序的好时机。这对于长时间运行的应用程序非常有用。实际执行的优化完全取决于实现,并且将来可能会在不通知的情况下更改。[Feature #18885]
-
-
-
Process::Status#& 和 Process::Status#>> 已弃用。[Bug #19868]
-
-
-
Range#reverse_each现在可以处理带有Integer终点的无开始范围。[Feature #18515] -
Range#reverse_each现在对无尽范围会引发TypeError。[Feature #18551] -
添加了
Range#overlap?,用于检查两个范围是否重叠。[Feature #19839]
-
-
-
添加了
Refinement#target作为 Refinement#refined_class 的替代。Refinement#refined_class 已弃用,将在 Ruby 3.4 中移除。[Feature #19714]
-
-
-
基于缓存的优化现在支持后行断言和原子分组。也就是说,对于包含这些扩展的
Regexp的匹配现在可以在线性时间内完成,相对于输入字符串的长度。但是,它们不能包含捕获组,也不能嵌套。[Feature #19725]
-
-
-
String#unpack现在对未知指令会引发ArgumentError。[Bug #19150] -
String#bytesplice现在接受新的参数,用于指定要复制的源字符串的索引/长度或范围。[Feature #19314]
-
-
-
Thread::Queue#freeze现在会引发TypeError。[Bug #17146]
-
-
-
使用字符串参数的
Time.new变得更严格了。[Bug #19293]Time.new('2023-12-20') # no time information (ArgumentError)
-
-
-
TracePoint支持rescue事件。当捕获到抛出的异常时,TracePoint会触发钩子。rescue事件仅支持 Ruby 级别的rescue。[Feature #19572]
-
标准库更新
-
RubyGems 和
Bundler会在用户没有将以下 gem 添加到 Gemfile 或 gemspec 而直接require时发出警告。这是因为它们将在 Ruby 的未来版本中成为捆绑 gem。如果您使用 bootsnap gem,则会抑制此警告。我们建议至少运行一次您的应用程序,并设置DISABLE_BOOTSNAP=1环境变量。这是此版本的限制。[Feature #19351] [Feature #19776] [Feature #19843]-
abbrev
-
base64
-
bigdecimal
-
csv
-
drb
-
getoptlong
-
mutex_m
-
nkf
-
observer
-
racc
-
resolv-replace
-
rinda
-
syslog
-
abbrev
-
base64
-
bigdecimal
-
csv
-
drb
-
getoptlong
-
mutex_m
-
nkf
-
observer
-
racc
-
resolv-replace
-
rinda
-
syslog
-
-
Socket#recv和Socket#recv_nonblock在连接关闭时返回nil而不是空字符串。Socket#recvmsg和Socket#recvmsg_nonblock在连接关闭时返回nil而不是空数据包。[Bug #19012] -
名称解析(例如
Socket.getaddrinfo、Socket.getnameinfo、Addrinfo.getaddrinfo等)现在可以被中断了。[Feature #19965] -
Random::Formatter#alphanumeric已扩展,可以接受可选的chars关键字参数。[Feature #18183]
添加了以下默认 gem。
-
prism 0.19.0
更新了以下默认 gem。
-
RubyGems 3.5.3
-
abbrev 0.1.2
-
base64 0.2.0
-
benchmark 0.3.0
-
bigdecimal 3.1.5
-
bundler 2.5.3
-
cgi 0.4.1
-
csv 3.2.8
-
date 3.3.4
-
delegate 0.3.1
-
drb 2.2.0
-
english 0.8.0
-
erb 4.0.3
-
error_highlight 0.6.0
-
etc 1.4.3
-
fcntl 1.1.0
-
fiddle 1.1.2
-
fileutils 1.7.2
-
find 0.2.0
-
getoptlong 0.2.1
-
io-console 0.7.1
-
io-nonblock 0.3.0
-
io-wait 0.3.1
-
ipaddr 1.2.6
-
irb 1.11.0
-
json 2.7.1
-
logger 1.6.0
-
mutex_m 0.2.0
-
net-http 0.4.0
-
net-protocol 0.2.2
-
nkf 0.1.3
-
observer 0.1.2
-
open-uri 0.4.1
-
open3 0.2.1
-
openssl 3.2.0
-
optparse 0.4.0
-
ostruct 0.6.0
-
pathname 0.3.0
-
pp 0.5.0
-
prettyprint 0.2.0
-
pstore 0.1.3
-
psych 5.1.2
-
rdoc 6.6.2
-
readline 0.0.4
-
reline 0.4.1
-
resolv 0.3.0
-
rinda 0.2.0
-
securerandom 0.3.1
-
set 1.1.0
-
shellwords 0.2.0
-
singleton 0.2.0
-
stringio 3.1.0
-
strscan 3.0.7
-
syntax_suggest 2.0.0
-
syslog 0.1.2
-
tempfile 0.2.1
-
time 0.3.0
-
timeout 0.4.1
-
tmpdir 0.2.0
-
tsort 0.2.0
-
un 0.3.0
-
uri 0.13.0
-
weakref 0.1.3
-
win32ole 1.8.10
-
yaml 0.3.0
-
zlib 3.1.0
以下捆绑 gem 已从默认 gem 升级。
-
racc 1.7.3
以下捆绑 gem 已更新。
-
minitest 5.20.0
-
rake 13.1.0
-
test-unit 3.6.1
-
rexml 3.2.6
-
rss 0.3.0
-
net-ftp 0.3.3
-
net-imap 0.4.9
-
net-smtp 0.4.0
-
rbs 3.4.0
-
typeprof 0.21.9
-
debug 1.9.1
有关默认 gem 或捆绑 gem 的详细信息,请参阅 GitHub releases,如 Logger 或 changelog。
Prism
-
引入了 Prism 解析器 作为默认 gem。
-
Prism是一个可移植、容错且易于维护的 Ruby 语言递归下降解析器。
-
-
Prism已准备好投入生产并积极维护,您可以将其替代Ripper使用。-
Prism既是一个 C 库(将由 CRuby 内部使用),也是一个 Ruby gem,可以被任何需要解析 Ruby 代码的工具使用。 -
PrismAPI 中的重要方法包括:-
Prism.parse(source),它返回 AST 作为解析结果对象的一部分。 -
Prism.parse_comments(source),它返回注释。 -
Prism.parse_success?(source),如果没有任何错误,则返回 true。
-
-
如果您有兴趣贡献,可以直接在 Prism 仓库 上创建 pull requests 或 issues。
-
您现在可以使用
ruby --parser=prism或RUBYOPT="--parser=prism"来尝试Prism编译器。请注意,此标志仅用于调试。
兼容性问题
-
通过以下文件打开方法创建子进程/forking 已弃用。[Feature #19630]
-
当
Kernel#lambda接收到一个非 lambda、非字面量的块时,现在会引发ArgumentError,而不是将其原样返回。自 Ruby 3.0.0 起,这些用法已在Warning[:deprecated]类别下发出警告。[Feature #19777] -
环境变量
RUBY_GC_HEAP_INIT_SLOTS已弃用并移除。应使用环境变量RUBY_GC_HEAP_%d_INIT_SLOTS。[Feature #19785] -
在没有普通参数的块中调用不带参数的
it已弃用。在 Ruby 3.4 中,it将成为第一个块参数的引用。[Feature #18980] -
NoMethodError的错误消息已更改,为提高效率不再使用目标对象的 inspect,而是显示“instance of ClassName”。[Feature #18285]([1] * 100).nonexisting # undefined method `nonexisting' for an instance of Array (NoMethodError)
-
现在不允许在使用匿名参数的块内部转发匿名参数。[Feature #19370]
标准库兼容性问题
-
racc已升级为捆绑 gem。-
如果您在 bundler 环境中使用
racc,则需要将racc添加到您的Gemfile中。
-
-
ext/readline已淘汰。-
我们有
reline,它是纯 Ruby 实现,兼容ext/readlineAPI。我们将来依赖reline。如果您需要使用ext/readline,可以通过 rubygems.org 安装ext/readline,命令为gem install readline-ext。 -
我们不再需要安装
libreadline或libedit等库。
-
C API 更新
-
rb_postponed_job更新。 -
新增 API 和已弃用的 API(详情请参阅注释)。
-
新增:
rb_postponed_job_preregister() -
新增:
rb_postponed_job_trigger() -
已弃用:
rb_postponed_job_register()(语义也有所改变,见下文)。 -
已弃用:
rb_postponed_job_register_one() -
新增:
rb_postponed_job_preregister() -
新增:
rb_postponed_job_trigger() -
已弃用:
rb_postponed_job_register()(语义也有所改变,见下文)。 -
已弃用:
rb_postponed_job_register_one()
-
-
rb_postponed_jobAPI 已更改,以解决一些罕见的崩溃问题。为了解决这个问题,我们引入了两个新 API 并弃用了现有 API。这些函数语义也略有变化;rb_postponed_job_register现在表现得像once变体,即多次使用相同的func调用可能会合并为对func的一次执行。[Feature #20057] -
对内部线程事件钩子 API 进行了一些更新。
-
rb_internal_thread_event_data_t带有目标 Ruby 线程 (VALUE) 和回调函数 (rb_internal_thread_event_callback) 将接收它。github.com/ruby/ruby/pull/8885 -
引入了以下函数,用于从内部线程事件钩子 API 操作 Ruby 线程本地数据(自 Ruby 3.2 起引入)。[github.com/ruby/ruby/pull/8936]
-
rb_internal_thread_specific_key_create() -
rb_internal_thread_specific_get() -
rb_internal_thread_specific_set()
-
-
引入了
rb_profile_thread_frames(),用于获取特定线程的帧。[Feature #10602] -
引入了
rb_data_define(),用于定义Data。[Feature #19757] -
引入了
rb_ext_resolve_symbol(),用于从扩展库中搜索函数。[Feature #20005] -
IO相关更新。 -
rb_io_t的细节将被隐藏,并为每个成员添加了已弃用的属性。[Feature #19057] -
引入了
rb_io_path(VALUE io),用于获取io的路径。 -
引入了
rb_io_closed_p(VALUE io),用于获取io的打开或关闭状态。 -
引入了
rb_io_mode(VALUE io),用于获取io的模式。 -
引入了
rb_io_open_descriptor(),用于从文件描述符创建IO对象。
实现改进
Parser
-
用 Lrama LALR 解析器生成器 替换了 Bison。现在从源代码构建 Ruby 不再需要安装 Bison。我们将不再受 Bison 兼容性问题的困扰,并且可以通过仅在 Lrama 中实现新功能来使用它们。[Feature #19637]
-
有关详细信息,请参阅 Ruby 解析器的未来愿景。
-
Lrama 的内部解析器是 Racc 生成的 LR 解析器,便于维护。
-
支持参数化规则
(?, *, +),将在 Ruby parse.y 中使用。
GC / 内存管理。
-
与 Ruby 3.2 相比,性能大幅提升。
-
旧对象引用的年轻对象不再立即提升到旧代。这显著减少了主要
GC收集的频率。[Feature #19678] -
引入了一个新的
REMEMBERED_WB_UNPROTECTED_OBJECTS_LIMIT_RATIO调整变量,用于控制导致主要GC收集触发的未受保护对象的数量。默认值为0.01(1%)。这显著减少了主要GC收集的频率。[Feature #19571] -
为许多缺少写屏障的核心类型实现了写屏障,特别是
Time、Enumerator、MatchData、Method、File::Stat、BigDecimal等。这显著减少了次要GC收集的时间和主要GC收集的频率。 -
大多数核心类现在使用可变宽度分配,特别是
Hash、Time、Thread::Backtrace、Thread::Backtrace::Location、File::Stat、Method。这使得这些类的分配和释放更快,占用内存更少,并减少了堆碎片。
-
-
defined?(@ivar)已通过ObjectShapes 进行优化。
YJIT
-
与 Ruby 3.2 相比,性能大幅提升。
-
对 splat 和 rest 参数的支持得到了改进。
-
为虚拟机堆栈操作分配了寄存器。
-
编译了更多带有可选参数的调用。
Exception处理程序也得到了编译。 -
不支持的调用类型和多态调用站点不再退出到解释器。
-
Rails 的 blank? 和 专门的
#present?等基本方法已内联。 -
Integer#*、Integer#!=、String#!=、String#getbyte、Kernel#block_given?、Kernel#is_a?、Kernel#instance_of?和Module#===得到了特殊的优化。 -
编译速度现在比 Ruby 3.2 稍快。
-
在 Optcarrot 上现在比解释器快 3 倍以上!
-
与 Ruby 3.2 相比,内存使用量显著降低。
-
已编译代码的元数据占用的内存更少。
-
当应用程序拥有超过 40,000 个 ISEQs 时,
--yjit-call-threshold会从 30 自动提高到 120。 -
添加了
--yjit-cold-threshold来跳过编译冷 ISEQs。 -
在 Arm64 上生成更紧凑的代码。
-
-
代码
GC现在默认禁用。 -
--yjit-exec-mem-size被视为硬限制,新的代码编译将在达到此限制时停止。 -
如果您愿意,仍然可以通过
--yjit-code-gc启用代码GC。 -
添加了
RubyVM::YJIT.enable,可以在运行时启用 YJIT。 -
您无需修改命令行参数或环境变量即可启动 YJIT。Rails 7.2 将使用此方法 默认启用 YJIT。
-
这也可以用于在应用程序完成引导后仅启用 YJIT。如果您想在引导时禁用 YJIT 时使用其他 YJIT 选项,可以使用
--yjit-disable。 -
默认提供更多 YJIT 统计信息。
-
yjit_alloc_size和其他几个与元数据相关的统计信息现在默认可用。 -
--yjit-stats生成的ratio_in_yjit统计信息现在可在发布版本中使用,无需特殊统计或开发版本即可访问大多数统计信息。 -
增加了更多分析能力。
-
添加了
--yjit-perf,以便使用 Linux perf 进行分析。 -
--yjit-trace-exits现在支持使用--yjit-trace-exits-sample-rate=N进行采样。 -
更全面的测试和多项 bug 修复。
-
添加了
--yjit-stats=quiet,以避免在退出时打印统计信息。
MJIT
-
MJIT 已移除。
-
--disable-jit-support已移除。请考虑使用--disable-yjit --disable-rjit。
-
RJIT
-
引入了一个纯 Ruby JIT 编译器 RJIT。
-
RJIT 仅支持 Unix 平台上的 x86_64 架构。
-
与 MJIT 不同,它在运行时不需要 C 编译器。
-
-
RJIT 仅用于实验目的。
-
您应该继续在生产环境中使用 YJIT。
-
M:N Thread 调度器。
-
引入了 M:N
Thread调度器。[Feature #19842]-
背景:Ruby 1.8 及之前版本,使用了 M:1 线程调度器(M 个 Ruby 线程对应 1 个原生线程。称为用户级线程或绿色线程)。Ruby 1.9 及之后版本,使用了 1:1 线程调度器(1 个 Ruby 线程对应 1 个原生线程)。M:1 线程比 1:1 线程占用更少的资源,因为只需要 1 个原生线程。但是,由于难以支持所有阻塞操作的上下文切换,因此从 Ruby 1.9 开始采用了 1:1 线程。M:N 线程调度器使用 N 个原生线程来管理 M 个 Ruby 线程(N 通常是一个较小的数字)。它不需要与 Ruby 线程相同数量的原生线程(类似于 M:1 线程调度器)。此外,我们的 M:N 线程支持阻塞操作的性能与 1:1 线程相同。有关更多详细信息,请参阅 ticket。我们的 M:N 线程调度器参考了 Go 语言中的 goroutine 调度器。
-
在 Ractor 中,由于实现原因,同一时间只能运行 1 个线程。因此,仅使用一个
Ractor的应用程序(大多数应用程序)M:N 线程调度器的工作方式类似于 M:1 线程调度器,并具有 Ruby 1.8 的扩展功能。 -
M:N 线程调度器可能会引入 C 扩展的不兼容性,因此默认在主 Ractor 上禁用。设置
RUBY_MN_THREADS=1环境变量将启用它。在非主 Ractor 上,M:N 线程调度器是启用的(现在无法禁用)。 -
N(原生线程数)可以通过RUBY_MAX_CPU环境变量指定。默认为 8。请注意,使用超过N个原生线程来支持多种阻塞操作。
-