( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

Rails3でMultiJsonのBackendをyajlに変更してJSONのエンコード/デコードのパフォーマンスを改善する

yajl(Yet Another JSON Library)っていう高速なJSONライブラリがあって、

yajl


こいつをrubyから使えるようにするyajl-rubyってgemがあって、これをMultiJsonのBackendに変更することで、RailsにおけるJSON処理の高速化が期待できるデス。

brianmario/yajl-ruby · GitHub


素のjson.gemと、yajl-rubyとで適当なActiveRecordオブジェクトからJSONへのエンコードと、その逆のデコードで簡単にベンチってみると、約2倍の差があることが分かる。

--------------------------------------------------------------------------------
Benchmark of json encoding/decoding
  json_gem vs yajl
--------------------------------------------------------------------------------

                                            | json_gem |    yajl | json_gem/yajl |
--Single ActiveRecord Object -----------------------------------------------------
encode                               x10000 |   12.130 |   6.167 |         1.97x |
decode                               x10000 |    1.085 |   0.437 |         2.48x |
--Array  ActiveRecord Objects-----------------------------------------------------
encode                               x10000 |  508.319 | 225.235 |         2.26x |
decode                               x10000 |   39.069 |  19.869 |         1.97x |

MultiJsonのBackendをyajlに変えたら素のjson.gemの2倍のパフォーマンスになった件


MultiJsonは、yajl-rubyがあると自動的にそっちを見るようになってるので、gem 'yajl-ruby'するだけでjsonの処理が高速化する、とおもいきや……


ActiveSupport::JSONのコードを見てみると、JSONのデコード時にはMultiJsonを利用するようになっているが、エンコードする際にはActiveSupport独自の実装でエンコードするようになっている。この理由としては、ActiveSupportAPIと他のライブラリの実装で互換性がないかもしれない、という話みたいだ。

Endoding with yajl-ruby for rails 3 · Issue #40 · brianmario/yajl-ruby · GitHub


とはいえ、オブジェクトをActiveSupportのas_jsonでHashにしてしまって、それをyajlでJSONにエンコードすれば問題ないはず。ということで、このようなパッチを書いた。

MultiJson.engine = :yajl unless MultiJson.engine == MultiJson::Adapters::Yajl

module ActiveSupport
  module JSON
    def self.encode(value, options = nil)
      hash = ActiveSupport::JSON::Encoding::Encoder.new(options).as_json(value)
      MultiJson.encode(hash)
    end
  end
end

JSONを大量にやりとりする系のアプリケーションには多少のパフォーマンス改善が期待できる、はず。