Tech Racho エンジニアの「?」を「!」に。
  • 開発

Ruby: `&:メソッド名`はブロック変数渡しより若干高速

&:メソッド名はブロック変数渡しより若干高速

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.068287s

Comparison:
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.012293s

Comparison:
Symbol#to_proc: 75242.7 i/s
Block: 66699.0 i/s – 1.13x slower

おまけ

週刊Railsウォッチ(20190107)より。

トリビアですが、&:の間にはスペースがあっても動作は同じです。

[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: `&:メソッド名`はブロック変数渡しより若干高速

これTracePoint( https://docs.ruby-lang.org/ja/latest/class/TracePoint.html )を使って詳細を比較してみると分かる。&:の方が出力されるトレースが少なくてその分速い(って以前纏めた記憶あるけど何処に書いたか忘れた。。

2019/07/15 15:10

関連記事

Mac: Parallels Desktop for MacでUbuntu Server LTS環境を構築する


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。