【Unity】Protocol Buffers と JSON のパフォーマンス速度を比較した話

はじめに

はめまして、カヤックのゲーム技研の Unity エンジニアのアフィフです。

カヤックで運用しているゲームタイトルでは、主に JSON フォーマットでデータを管理していましたが、最近ではゲームのデータ量がどんどん増えていく傾向にあり、データの読み込みがボトルネックになりつつあります。

JSON のデシリアライズは結構遅いので、もっと良いデータフォーマットがないかと探したところ、Protocol Buffers というデータフォーマットを見つけました。 今回は、プロジェクトに導入する前にパーフォマンスを検証した結果について書きます。

Protocol Buffersとは

Protocol Buffers は Google により開発されているバイナリベースのデータフォーマットです。JSON 形式はテキストベースのデータフォーマットなので、オーバヘッドがあります。

例えば、この JSON のデータ容量は 32bytes です。

{"type":"ping","time":123456789}

{ " : } などの記号分は 2+3+3+2+1=11、 文字列分は 4+4+4=12 ですので、このデータタイプの容量の効率は 23/32bytes = 71% です。

Protocol Buffers であれば、上記のデータ容量は 7bytes だけで済みます。

0A 05 08 95 9A EF 3A

容量的には Protocol Buffers の方が効率がいいと思いますが、次はシリアライズ/デシリアライズの速度は JSON よりどれぐらい早くなるのを調査してみます。

※ Protocol Buffers について詳しく知りたい方はこちらを参考にしてください。

シリアライズ/デシリアライズのベンチマーク

サンプルデータ

今回の検証では、より実運用に近い結果を得るため、実際にカヤックで運用しているゲームタイトルのデータを加工して使用しました。

  • special.json (70KB)
  • unit.json (3.1MB)
  • special.pb (42KB)
  • unit.pb (806KB)

例えば、unit.json には12000件データが入っています。

パーサー

調査したパーサーは Unity3d の JsonUtility と人気のある Newtonsoft のライブラリと Google の Protocol Buffers で比較しました。

UnityEngine.JsonUtility

SpecialsData specialsData = JsonUtility.FromJson<SpecialsData>(specialsJson);

Newtonsoft.Json

SpecialsData specialsData = JsonConvert.DeserializeObject<SpecialsData>(specialsJson);

ProtocolBuffer

SpecialsData specialsData = SpecialsData.Parser.ParseFrom(specialsPb);

Samsung Galaxy J1 Mini (Android)

Parser Parse Time Memory Allocation
SpecialsData - UnityEngine.JsonUtility 16 ms 0 bytes
SpecialsData - Newtonsoft.Json 49 ms 40960 bytes
SpecialsData - ProtocolBuffers 6 ms 4096 bytes
UnitsData - UnityEngine.JsonUtility 474 ms 0 bytes
UnitsData - Newtonsoft.Json 2172 ms 266240 bytes
UnitsData - ProtocolBuffers 86 ms 106496 bytes

f:id:fjt_dentyu:20170311000059p:plain:w300 f:id:fjt_dentyu:20170311000103p:plain:w300

IPhone 6S Plus (iOS)

Parser Parse Time Memory Allocation
SpecialsData - UnityEngine.JsonUtility 9 ms 0 bytes
SpecialsData - Newtonsoft.Json 27 ms 73728 bytes
SpecialsData - ProtocolBuffers 3 ms 16384 bytes
UnitsData - UnityEngine.JsonUtility 88 ms 0 bytes
UnitsData - Newtonsoft.Json 327 ms 1204224 bytes
UnitsData - ProtocolBuffers 30 ms 69632 bytes

f:id:fjt_dentyu:20170311000136p:plain:w300 f:id:fjt_dentyu:20170311000141p:plain:w300

検証結果は UnityEngine.JsonUtility の方が Newtonsoft.Json より速いという結果になりました。

また、 UnityEngine.JsonUtility のメモリアロケーションがゼロとなっていることを確認できました。ただ UnityEngine.JsonUtility は機能性がそれほど高くはないです。 Newtonsoft.Json は、設定によってパーフォマンスは多少変わってくるので、条件次第では Newtonsoft.Json はもっと良い結果を出すことが可能だと思います。 Protocol Buffers のデシリアライズは JSON よりも圧倒的に高速です。メモリアロケーションも Newtonsoft.Json よりも少なくて済みます。

終わりに

確かに Protocol Buffers の方がパフォーマンスは良さそうですが、JSON は文字列なので、ログとしてそのまま保持するだけで調査がしやすいなどのメリットがあります。Protocol Buffers はデシリアライズしないと人間が読むことができません。 Protocol Buffers も JSON もそれぞれメリットとデメリットがありますので、最適なほうを検討してみてはどうでしょうか。

カヤックでは一緒に働きたい方をいつでも募集中です!

関連記事

techblog.kayac.com

techblog.kayac.com