&:メソッド名
はブロック変数渡しより若干高速
Use fast ruby idioms by oniofchaos · Pull Request #32337 · rails/railsのしょっぱなに、ブロック変数を用いるブロック渡しより、&:メソッド名
渡しの方が高速だと説明されています。
require 'benchmark/ips'
RANGE = (1..100)
def slow
RANGE.map { |i| i.to_s }
end
def fast
RANGE.map(&:to_s)
end
Benchmark.ips do |x|
x.report('Block') { slow }
x.report('Symbol#to_proc') { fast }
x.compare!
end
Ubuntu 18.4.2 LTS(macOS環境のParallels DesktopのVM上)のRuby 2.6.3で実行してみると、誤差の範囲とはいえ、&:メソッド名
の方がわずかに高速です。なお、実行にはgem install benchmark-ips
をやっておく必要があります。
ruby block-vs-to_proc.rb
Warming up --------------------------------------
Block 7.317k i/100ms
Symbol#to_proc 8.042k i/100ms
Calculating -------------------------------------
Block 70.244k (± 6.8%) i/s - 351.216k in 5.026038s
Symbol#to_proc 76.526k (± 6.5%) i/s - 386.016k in 5.068287sComparison:
Symbol#to_proc: 76525.7 i/s
Block: 70243.9 i/s - same-ish: difference falls within error
なお、macOS Mojave環境のRuby 2.6.3だともう少し差が開きました。いずれも数回回してみましたが、参考値ということで。
ruby block-vs-to_proc.rb
Warming up --------------------------------------
Block 6.854k i/100ms
Symbol#to_proc 6.607k i/100ms
Calculating -------------------------------------
Block 66.699k (± 8.0%) i/s - 335.846k in 5.077837s
Symbol#to_proc 75.243k (± 3.6%) i/s - 376.599k in 5.012293sComparison:
Symbol#to_proc: 75242.7 i/s
Block: 66699.0 i/s - 1.13x slower
その後, M1 Macbook Pro 2021とRuby 3.1.2でもやってみました。
$ ruby -v
ruby 3.1.2p20 (2022-04-12 revision 4491bb740a) [arm64-darwin21]
$ ruby block-vs-to_proc.rb
Warming up --------------------------------------
Block 14.991k i/100ms
Symbol#to_proc 18.080k i/100ms
Calculating -------------------------------------
Block 150.803k (± 0.5%) i/s - 764.541k in 5.069937s
Symbol#to_proc 179.763k (± 4.3%) i/s - 904.000k in 5.041927s
Comparison:
Symbol#to_proc: 179763.2 i/s
Block: 150803.1 i/s - 1.19x (± 0.00) slower
おまけ
トリビアですが、&
と:
の間にはスペースがあっても動作は同じです。
[1, 2, 3].select(&:even?)
[1, 2, 3].select(& :even?)
RubyのRipperなどでパーサーの動きを確認できます。
require 'ripper'
Ripper.sexp('[1, 2, 3].select(&:even?)')
Ripper.sexp('[1, 2, 3].select(& :even?)')
おたより発掘
Ruby: `&:メソッド名`はブロック変数渡しより若干高速
- [ruby]
これTracePoint( https://docs.ruby-lang.org/ja/latest/class/TracePoint.html )を使って詳細を比較してみると分かる。&:の方が出力されるトレースが少なくてその分速い(って以前纏めた記憶あるけど何処に書いたか忘れた。。
更新情報