Enumrableにprocオブジェクトを渡すとメソッドを渡した時のように実行してくれます。
このとき、procオブジェクト自体は外に出すか、素直にブロックを使うようにしないと、かなり遅くなります。
実際のところ
0を渡すと「A:1」、5なら「F:6」という感じの文字列を返す処理を考えます。
実装として、
- procを外でつくって渡す
- procを毎回生成して渡す
- ブロック内に記述する
の三パターンを考えてみます。
ベンチマークは以下の通り。
require 'benchmark/ips' Benchmark.ips do |x| proc =-> x { %Q(#{(0x41 + x).chr}:#{x.next})} x.report('proc') { [1,2,3].map(&proc)} x.report('proc(arvg)') { [1,2,3].map(&->x{%Q(#{(0x41 + x).chr}:#{x.next})})} x.report('block') { [1,2,3].map{|x| %Q(#{(0x41 + x).chr}:#{x.next}) } } x.compare! end
さっそく実行してみると……
Calculating ------------------------------------- proc 35.663k i/100ms proc(arvg) 22.353k i/100ms block 36.191k i/100ms ------------------------------------------------- proc 518.657k (±10.2%) i/s - 2.568M proc(arvg) 349.988k (±11.1%) i/s - 1.744M block 515.502k (± 9.0%) i/s - 2.570M Comparison: proc: 518656.8 i/s block: 515502.0 i/s - 1.01x slower proc(arvg): 349987.6 i/s - 1.48x slower
毎回渡すパターンがすごい結果になりました。
……遅いとはわかっていましたが、まさかここまでとは……
二倍したものをmapするといったような単純な処理の場合、この差はさらに広がります。
なので、procを渡す場合は変に色気を出さないで外に出したほうがいいです。