先日の find_allのindex版( http://qiita.com/pocari/items/0b4e632ef2a2b6a97ba9 )という記事を受けて。
- ruby 1.9
- ruby 2.0
- ruby 2.1
- jruby1.7.12 --1.9
- jruby1.7.12 --2.0
の5つの環境で速度がどう変わるか調べてみたよ。
わかったこと
※ すべて、今回のベンチマークの範囲の話。一般的かどうかはわからない。
-
each_with_index.select
やflat_map.with_index
は、ruby 1.9 → 2.0 → 2.1 と、すごく速くなっている。都合 10倍以上。 - CRuby だと、
each_with_index
とeach.with_index
は、同じっぽい。 - JRuby だと、
each_with_index
よりeach.with_index
がの方が速い。 -
flat_map.with_index{}
より、map.with_index{}.compact
の方が速かった。意外。 -
--1.9
と--2.0
の速度差はほとんどない。
結果
ruby 1.9
"ruby 1.9.3p545 (2014-02-24 revision 45159) [x86_64-darwin13.0.0]"
size : 5000000
user system total real
each_with_index.select: 7.130000 0.010000 7.140000 ( 7.145922)
each.with_index.select: 7.160000 0.010000 7.170000 ( 7.170584)
map.with_index{}.compact: 0.580000 0.030000 0.610000 ( 0.628142)
flat_map.with_index: 7.180000 0.010000 7.190000 ( 7.189736)
size.times.select: 0.430000 0.000000 0.430000 ( 0.433888)
ruby 2.0
"ruby 2.0.0p481 (2014-05-08 revision 45883) [x86_64-darwin13.3.0]"
size : 5000000
user system total real
each_with_index.select: 3.930000 0.010000 3.940000 ( 3.936129)
each.with_index.select: 3.980000 0.000000 3.980000 ( 3.984897)
map.with_index{}.compact: 0.560000 0.030000 0.590000 ( 0.609218)
flat_map.with_index: 3.950000 0.000000 3.950000 ( 3.954283)
size.times.select: 0.410000 0.000000 0.410000 ( 0.411161)
ruby 2.1
"ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]"
size : 5000000
user system total real
each_with_index.select: 0.690000 0.000000 0.690000 ( 0.683463)
each.with_index.select: 0.690000 0.000000 0.690000 ( 0.693749)
map.with_index{}.compact: 0.510000 0.030000 0.540000 ( 0.556931)
flat_map.with_index: 0.680000 0.000000 0.680000 ( 0.679448)
size.times.select: 0.380000 0.000000 0.380000 ( 0.380963)
jruby1.7.12 --1.9
"jruby 1.7.12 (1.9.3p392) 2014-04-15 643e292 on Java HotSpot(TM) 64-Bit Server VM 1.7.0_07-b10 [darwin-x86_64]"
size : 5000000
user system total real
each_with_index.select: 1.670000 0.020000 1.690000 ( 1.466000)
each.with_index.select: 0.860000 0.000000 0.860000 ( 0.829000)
map.with_index{}.compact: 0.620000 0.010000 0.630000 ( 0.540000)
flat_map.with_index: 0.780000 0.000000 0.780000 ( 0.709000)
size.times.select: 0.430000 0.000000 0.430000 ( 0.368000)
jruby1.7.12 --2.0
"jruby 1.7.12 (2.0.0p195) 2014-04-15 643e292 on Java HotSpot(TM) 64-Bit Server VM 1.7.0_07-b10 [darwin-x86_64]"
size : 5000000
user system total real
each_with_index.select: 1.630000 0.020000 1.650000 ( 1.427000)
each.with_index.select: 0.880000 0.010000 0.890000 ( 0.853000)
map.with_index{}.compact: 0.630000 0.010000 0.640000 ( 0.528000)
flat_map.with_index: 0.760000 0.000000 0.760000 ( 0.710000)
size.times.select: 0.390000 0.000000 0.390000 ( 0.358000)
利用したプログラム
p RUBY_DESCRIPTION
require "benchmark"
def run_bench( size )
puts "size : #{size}"
ary = Array.new(size){ rand(size) }
Benchmark.bm(28) do |x|
def x.rep(s); report( "%28s" % s ){ yield }; end
r=[]
x.rep("each_with_index.select:"){
r<<ary.each_with_index.select{ |v,ix| v<5 }.map(&:last)
}
x.rep("each.with_index.select:"){
r<<ary.each.with_index.select{ |v,ix| v<5 }.map(&:last)
}
x.rep("map.with_index{}.compact:"){
r<<ary.map.with_index{ |v,ix| v<5 ? ix : nil }.compact
}
x.rep("flat_map.with_index:"){
r<<ary.flat_map.with_index{ |v,ix| v<5 ? [ix] : [] }
}
x.rep("size.times.select:"){
r<<ary.size.times.select{ |i| ary[i]<5 }
}
puts "**NG**" unless r.uniq.size==1
end
end
run_bench( 5000000 )
結論
-
each_with_index
よりもeach.with_index
を使ったほうがいいかもね。 - ruby 2.1 は素晴らしいね!
- 開発者の皆様 ありがとう!