はじめに
はめまして、カヤックのゲーム技研の 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 |
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 |
検証結果は 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 もそれぞれメリットとデメリットがありますので、最適なほうを検討してみてはどうでしょうか。