mruby-jsonとmruby-msgpackの速度比較してみた!
はじめに
JSONとMessagePackでは、シリアライズとデシリアライズにおいて、MessagePackがバイナリフォーマットなので、数倍速いです。今回はmruby版でシリアライズとデシリアライズの速度を比べてみようと思います。 ちなみにシリアライズはデータをファイルに保存したり、ネットワークで送受信できるようにすることです。反対に、デシリアライズとはシリアライズしたファイルやネットワーク上のデータをプログラムで扱えるように復元することです。
ビルド
1. build_config.rbにmruby-jsonとmruby-msgpackのconfig.gem行を追加:
MRuby::Build.new do |conf| # ...(省略)... conf.gem :git => 'https://github.com/mattn/mruby-json' conf.gem :git => 'https://github.com/suzukaze/mruby-msgpack.git' end
2.コマンドプロプトからビルド:
ruby ./minirake
ベンチマークプログラム
自分はmacを使用しているので、計測したいmrubyファイルをmrubyで実行して、timeコマンドで計測すればよいです。 time mruby mruby-benchmark.rb
ですが、いくつも計測するのに汎用的なベンチマークプログラムはないかと探しましたら、rubyの標準にBenchmarkモジュールがありました。 よさそうと思ったのですが、すべて理解するのは大変だったので、少し参考にしてmruby用に自作しました。
SimpleBenchmarkクラス
class SimpleBenchmark def initialize(width = 0) @width = width end def measure(label) start = Time.now yield if block_given? passed = Time.now - start puts "#{make_fixed_label(label)}passed time #{passed} sec" end def make_fixed_label(label) if @width - label.length > 0 label + ' ' * (@width - label.length) else label end end end
次のハッシュをシリアライズとデシリアライズをJSONとmsgpackで10000回繰り返します。
{'name' => 'suzukaze', 'level' => 15})
計測プログラムは次のようになります:
benchmark = SimpleBenchmark.new("MessagePack:".length) n = 10000 #JSONでシリアライズとデシリアライズする時間を計測する benchmark.measure("JSON:") do n.times{ JSON.parse(JSON.generate({'name' => 'suzukaze', 'level' => 15})) } end #MessagePackでシリアライズとデシリアライズする時間を計測する benchmark.measure("MessagePack:") do n.times{ MessagePack.unpack(MessagePack.pack({'name' => 'suzukaze', 'level' => 15})) } end
計測環境
OS:Mac OS X 10.8.4
プロセッサ: 2.13GHz intel Core 2 Duo
計測
次のコマンドをコマンドプロンプトから実行します:
mruby mruby-msgpack-profile.rb
mruby-msgpack-profile.rbは最後に全部、掲載しています。
計測結果
JSON: passed time 0.543839 sec MessagePack:passed time 0.092397 sec
計測結果はMessagePackがJSONの約5.8倍の速さとなりました。
最後に
計測に使ったソースの全文を掲載します。
mruby-msgpack-profile.rb
class SimpleBenchmark def initialize(width = 0) @width = width end def measure(label) start = Time.now yield if block_given? passed = Time.now - start puts "#{make_fixed_label(label)}passed time #{passed} sec" end def make_fixed_label(label) if @width - label.length > 0 label + ' ' * (@width - label.length) else label end end end benchmark = SimpleBenchmark.new("MessagePack:".length) n = 10000 #JSONでシリアライズとデシリアライズする時間を計測する benchmark.measure("JSON:") do n.times{ JSON.parse(JSON.generate({'name' => 'suzukaze', 'level' => 15})) } end #MessagePackでシリアライズとデシリアライズする時間を計測する benchmark.measure("MessagePack:") do n.times{ MessagePack.unpack(MessagePack.pack({'name' => 'suzukaze', 'level' => 15})) } end