
Fast-Ruby 项目整理 Ruby 高效惯用写法
来源标题:Fast-Ruby: Writing Fast Ruby – Collect Common Ruby Idioms
Fast-Ruby 项目汇总了能让 Ruby 代码跑得更快的常见惯用写法,灵感来自 Erik Michaels-Ober 在 Baruco 2014 的演讲《Writing Fast Ruby》。每种写法都配有基准测试代码和真实提交链接,结果基于 macOS 上的 Ruby 4.0.0 测出。作者提醒需按上下文谨慎替换,并推荐了静态分析工具 fasterer。
以下正文由 AI 翻译自 Hacker News 最新(原文版权归原站所有),可能存在偏差,重要内容请以原文为准。
在 Erik Michaels-Ober 那场精彩的演讲 “Writing Fast Ruby” 中(视频见 Baruco 2014,幻灯片),他向我们展示了许多能让 Ruby 代码跑得更快的惯用法。他启发我把这些记录下来,让更多人了解。我尽量链接到真实的 commit,这样大家就能看到这些做法在真实世界里确实能带来收益。但这并不意味着你总是可以盲目地用一替换另一,具体要看场景(比如 gsub 对 tr)。友情提醒:请谨慎使用!
每个惯用法在 code 目录下都有对应的代码示例。
README.md 中列出的所有结果都是在 macOS 15.6.1 上用 Ruby 4.0.0 跑出来的。机器信息:MacBook Pro(14 英寸,2024 年 11 月),Apple M4 Pro,48 GB 内存。你的结果可能不同,但大致思路是一样的。: )
你可以查看 GitHub Actions 的构建,了解这些 benchmark 结果在不同 Ruby 实现上的运行情况。
可以看看 fasterer 项目——它是一个静态分析工具,用来检查本仓库中涉及的速度惯用法。
require "benchmark/ips" def fast end def slow end Benchmark.ips do |x| x.report("fast code description") { fast } x.report("slow code description") { slow } x.compare! end
惯用法
索引
通用 数组 BigDecimal 日期 Enumerable 哈希 Proc 与 Block 字符串 时间 范围
通用
attr_accessor 对比 getter 和 setter 代码 https://www.rubydoc.info/stdlib/core/Module:attr_accessor
$ ruby -v code/general/attr-accessor-vs-getter-and-setter.rb ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin24] Warming up -------------------------------------- getter_and_setter 1.122M i/100ms attr_accessor 1.303M i/100ms Calculating ------------------------------------- getter_and_setter 10.999M (± 2.1%) i/s (90.92 ns/i) - 56.083M in 5.101077s attr_accessor 12.517M (± 1.5%) i/s (79.89 ns/i) - 63.841M in 5.101477s Comparison: attr_accessor: 12517008.0 i/s getter_and_setter: 10999275.5 i/s - 1.14x slower
begin...rescue 对比 respond_to? 用于控制流代码
$ ruby -v code/general/begin-rescue-vs-respond-to.rb ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin24] Warming up -------------------------------------- begin...rescue 230.601k i/100ms respond_to? 1.915M i/100ms Calculating ------------------------------------- begin...rescue 2.390M (± 0.9%) i/s (418.40 ns/i) - 11.991M in 5.017466s respond_to? 18.745M (± 1.8%) i/s (53.35 ns/i) - 93.843M in 5.007990s Comparison: respond_to?: 18744998.8 i/s begin...rescue: 2390076.1 i/s - 7.84x slower
define_method 对比 module_eval 用于定义方法代码
$ ruby -v code/general/define_method-vs-module-eval.rb ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin24] Warming up -------------------------------------- module_eval with string 630.000 i/100ms define_method 685.000 i/100ms Calculating ------------------------------------- module_eval with string 5.633k (±18.1%) i/s (177.53 μs/i) - 27.090k in 5.009884s define_method 7.239k (±17.6%) i/s (138.14 μs/i) - 34.250k in 5.040522s Comparison: define_method: 7238.9 i/s module_eval with string: 5632.8 i/s - 差不多:差异在误差范围内
上面的运行测的是旧代码,它在每次调用时生成 10 个随机名字,并定义在一个不断增长的类上。 下面的运行测的是当前代码,每次调用都在一个新类上定义同样的 10 个名字。
$ ruby -v code/general/define_method-vs-module-eval.rb ruby 4.0.7 (2026-09-15 revision 229531a6cf) +PRISM [aarch64-linux] Warming up -------------------------------------- define_method 15.939k i/100ms module_eval with string 2.507k i/100ms Calculating ------------------------------------- define_method 132.661k (±12.4%) i/s (7.54 μs/i) - 669.438k in 5.046213s module_eval with string 18.753k (±18.6%) i/s (53.32 μs/i) - 95.266k in 5.079985s Comparison: define_method: 132661.5 i/s module_eval with string: 18753.2 i/s - 7.07x slower
String#constantize 对比用于 inflect 的比较代码
ActiveSupport 的 String#constantize 会“解析接收者中的常量引用表达式”。
$ ruby -v code/general/constantize-vs-comparison.rb ruby 4.0.0 (2025-12-25 revision 553f1675f3) +PRISM [arm64-darwin24] Warming up -------------------------------------- using an if statement 1.507M i/100ms String#constantize 1.048M i/100ms Calculating ------------------------------------- using an if statement 15.518M (± 1.2%) i/s (64.44 ns/i) - 78.355M in 5.050041s String#constantize 10.556M (± 1.0%) i/s (94.73 ns/i) - 53.448M in 5.063570s Comparison: using an if statement: 15517955.2 i/s String#constantize: 10556362.4 i/s - 1.47x slower
方法 对比 转发方法 对比 委托方法代码
$ ruby -v code/general/method-vs-forwarded-method-vs-delegated-method.rb ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-darwin19] Warming up -------------------------------------- method 247.079k i/100ms forwarded method 183.323k i/100ms delegated method 136.666k i/100ms Calculating ------------------------------------- method 2.481M (± 0.5%) i/s - 12.601M in 5.078755s forwarded method 1.830M (± 0.8%) i/s - 9.166M in 5.009606s delegated method 1.365M (± 0.6%) i/s - 6.833M in 5.006191s Comparison: method: 2481182.0 i/s forwarded method: 1829835.8 i/s - 1.36x (± 0.00) slower delegated method: 1365026.7 i/s - 1.82x (± 0.00) slower
上面的运行来自那个 PR,当时委托方法的报告调用的是 pop(1)。 下面的运行测的是当前代码,三者都 push 1。
$ ruby -v code/general/method-vs-forwarded-method-vs-delegated-method.rb ruby 4.0.7 (2026-09-15 revision 229531a6cf) +PRISM [aarch64-linux] Warming up -------------------------------------- method 566.282k i/100ms forwarded method 452.579k i/100ms delegated method 222.869k i/100ms Calculating ------------------------------------- method 5.690M (± 1.0%) i/s (175.74 ns/i) - 28.880M in 5.075387s forwarded method 4.580M (± 3.9%) i/s (218.33 ns/i) - 23.082M in 5.039438s delegated method 2.229M (± 2.1%) i/s (448.72 ns/i) - 11.143M in 5.000248s Comparison: method: 5690282.1 i/s forwarded method: 4580179.6 i/s - 1.24x slower
(原文较长,此处译出前 6000 字,完整内容请点「打开原文」。)
正文由 探How 从来源站点 RSS 同步,内容未经改写;遇到排版缺失或需要图片、视频时请以原文为准。