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