RubyとJRubyとでパフォーマンスを比較してみた

Ruby

はじめに

以前Ruby(CRuby)で作成したアプリで、大量データ(数千万件オーバー)のCSVを読み込み、文字列変換をして別ファイルに出力するという処理を実装しました。同じような処理をRubyの別処理系で行った場合、どのようになるのかが気になったので、ちょっと実験してみました。

今回使う処理系や実行マシンについて

タイトルにもあるように、通常のRuby(CRuby)とJRubyとで比較しました。Rubyの他の処理系としてはRubiniusなどもありますが、それはまた別の機会にしたいと思います。

Ruby、JRubyのバージョンについて

今回使用したRuby、JRubyのバージョンは以下の通りです。

  • Ruby - 2.1.0
  • JRuby - 1.7.9

実行マシンについて

実行マシンについては以下の通りです。なおVirtualBox上のUbuntuで実行しています。

  • CPU - Core i7 2.80GHz
  • Momory - 8G
  • OS - Ubuntu 14.04 LTS

実行ソースと結果

実行ソース

実行したソースは以下の通りです。

benchmark.rb
INPUT_FILE_PATH = './input.csv'
OUTPUT_FILE_PATH = 'output.csv'

class DataDate
  def initialize(data_date)
    date_ary = data_date.split(' ')
    @date = date_ary[0]
    @time = date_ary[1]
  end

  def out_datetime
    ymd = @date.split('/')
    hm = @time.split(':')
    t = Time.new(ymd[0].to_i, ymd[1].to_i, ymd[2].to_i, hm[0].to_i, hm[1].to_i)
    t = t + (9 * 60 * 60)
    t.strftime('%Y-%m-%d %p %I:%M')
  end
end

def write_line(out, input)
  data = input.chomp.split(',')
  line = Array.new
  line << data[9].gsub('{#}', 'jjjj')
  line << data[8]
  line << data[7]
  line << data[6]
  line << data[5]
  line << data[4]
  line << data[3]
  line << data[2]
  line << data[1]
  line << DataDate.new(data[0]).out_datetime
  out.puts(line.join(','))
end

start_time = Time.now

open(OUTPUT_FILE_PATH, 'w'){|out|
  open(INPUT_FILE_PATH) {|input|
    input.each{|line|
      write_line(out, line)
    }
  }
}

end_time = Time.now

puts 'processing time = ' + (end_time - start_time).to_s

動きとしては

  • 100万件、10カラムのCSV(input.csv)を一行ずつ読み込む
  • 全カラムの左右並び順を入れ替える
  • 特定の文字列({#})を置き換える
  • 日付のフォーマットを変換する
  • これらの結果を別ファイル(output.csv)に出力する

といったことを行っております。

また読み込んだCSVファイル(input.csv)は以下のような書式となっております。

input.csv
2014/1/1 10:00,bbbbb,ccccc,ddddd,eeeee,fffff,ggggg,hhhhh,iiiii,j{#}
2014/1/2 10:00,bbbbb,ccccc,ddddd,eeeee,fffff,ggggg,hhhhh,iiiii,j{#}
2014/1/3 10:00,bbbbb,ccccc,ddddd,eeeee,fffff,ggggg,hhhhh,iiiii,j{#}
2014/1/4 10:00,bbbbb,ccccc,ddddd,eeeee,fffff,ggggg,hhhhh,iiiii,j{#}
2014/1/5 10:00,bbbbb,ccccc,ddddd,eeeee,fffff,ggggg,hhhhh,iiiii,j{#}
(以下略、100万件まで)

実行結果

上記のRubyスクリプトを、Ruby(CRuby)とJRubyとで5回ずつ実行してみました。但し、JRubyの実行時には最適化されるようオプションを設定しています。以下に、実行時のコマンドと5回の実行時間を載せておきます。

Ruby

ruby benchmark.rb
実行回数 時間(秒)
1回目 41.188
2回目 40.368
3回目 38.445
4回目 38.257
5回目 37.563

JRuby

jruby --server -v --fast benchmark.rb
実行回数 時間(秒)
1回目 29.338
2回目 28.285
3回目 27.143
4回目 29.536
5回目 30.598

平均すると

  • Ruby - 39.164秒
  • JRuby - 28.98秒
とJRubyのほうが早かったです。

まとめ

上記のような結果となりましたが、あくまで今回試したサンプルソースでの結果であるため、あらゆる場合でJRubyが早いとは限らないでしょう。またJRubyの実行時には最適化されるようオプションを設定したこともあり、これらを設定しない場合はJRubyのほうが遅かったことも合わせて書いておきます。

参考サイト

How JRuby Makes Ruby Fast