Rails3でMultiJsonのBackendをyajlに変更してJSONのエンコード/デコードのパフォーマンスを改善する
yajl(Yet Another JSON Library)っていう高速なJSONライブラリがあって、
こいつをrubyから使えるようにするyajl-rubyってgemがあって、これをMultiJsonのBackendに変更することで、RailsにおけるJSON処理の高速化が期待できるデス。
素の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独自の実装でエンコードするようになっている。この理由としては、ActiveSupportのAPIと他のライブラリの実装で互換性がないかもしれない、という話みたいだ。
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を大量にやりとりする系のアプリケーションには多少のパフォーマンス改善が期待できる、はず。