UnityでJson.NETとJsonUtilityのデシリアライズを比較してみる
たまにC#でJsonのデシリアライズをすることがあるんですけど、そのとき私はよくJson.NETを使うんですよね。「これが稀によくある」ってやつか!? ただ、毎回使い方を忘れているので使う度に調べる羽目になってしまっています。
そこで、今回はJson.NETでのデシリアライズ方法を過去のユースケースを用いて記録として残しておこうと思います。また、せっかくなんでUnityでのJson関連のAPIであるJsonUtilityのデシリアライズ方法も載せておきました。さらにどうせなので、この2つの処理性能を比較してみました。
実行環境
- macOS 10.15
- Unity2019.2.10f1
準備
Json.NETはAsset Storeにもあります。しかし、公式のJson.NETの最新バージョンに比べて少し古いバージョンを使っているようなので、今回は公式の最新リリースを使っていきます。
2019年11月1日時点では最新バージョンは 12.0.2 でした。上記ページからJson120r2.zipをダウンロードし、解凍した後Json120r2/Bin/net45以下にあるNewtonsoft.Json.dllをUnityプロジェクトのAssets/Plugins以下に配置します。
ケースその1
以下のデータからtype1のtimesを抽出してDateTimeのリストとして保存します。
{
"type1": {
"area": "tokyo",
"times": [
"2019-10-25 14:33",
"2019-10-20 23:51",
"2019-10-26 18:19",
"2019-10-20 21:08",
"2019-10-23 23:57",
"2019-10-23 23:43",
"2019-10-24 15:37",
"2019-10-25 04:14",
"2019-10-24 23:45"
]
},
"type2": {
"area": "kyoto",
"times": [
"2019-10-22 23:13",
"2019-10-25 13:19",
"2019-10-25 12:24",
"2019-10-20 07:06",
"2019-10-21 16:10",
"2019-10-22 11:49",
"2019-10-20 03:14",
"2019-10-21 21:33",
"2019-10-21 04:32"
]
}
}
Json.NETの場合はJson Utilityのようにパースするためのクラスを用意することなくリストを作成できるのがいいですね。リストを作成する際もLINQと合わせて使うことで直感的にデータを持ってくることができます。反対に、Json Utilityは使いたいデータがあるところまでの構造をクラスを使って再現してあげないといけません。このケースのようにネスト構造になっている場合はクラスを2つ作らないといけないため少し面倒ですね。ただ、必要なJsonフィールドの名前の変数だけ用意してあげればいいので少しは気が楽でしょうか?
処理の観測をする際は条件を整えるため1つずつ計測を行いました。例えば、Json.NETの観測をする際は上記コードのようにJson Utilityの部分をコメントアウトしています。
Profilerで見てみると以下の結果になっていました。
Json.NET

Json Utility

| JObject.Parse(Json.NET) | JsonUtility.FromJson(Json Utility) | |
|---|---|---|
| 速度(別メソッド呼び出し込み) | 16.61ms | 0.35ms |
| GC Alloc | 11.4KB | 2.8KB |
Json Utilityの方が高速で、さらにGC Allocも少ないという結果になりましたね。うーむ、これはUnityでは積極的にJson Utilityを使った方がいいのでは?
ケースその2
以下のゴミの捨て方のデータよりdataオブジェクトの配列中のitemとanswerの要素を持つクラスのリストを作ります。ちなみに、このデータはこちらのものを改変して作りました。
{
"limit": 50,
"lastUpdate": "2018-03-07 08:40:05",
"data": [
{
"oid": 1,
"item": "アイスクリームの容器",
"synonym": "アイスクリームの容器/アイス容器",
"answer": "1.紙製のものは「古紙類」として雑誌や新聞折込チラシと一緒に束ねて出してください。2.プラマークの表示があるものは「プラスチック製容器包装」として出してください ※ともに汚れが落ちないものは「燃やせるごみ」として出してください",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
},
{
"oid": 2,
"item": "アイスノン",
"synonym": "アイスノン/あいすのん",
"answer": "燃やせるごみ",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
},
{
"oid": 3,
"item": "アイロン",
"synonym": "アイロン/あいろん",
"answer": "燃やせないごみ",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
},
{
"oid": 4,
"item": "アイロン台",
"synonym": "アイロン台/あいろん台",
"answer": "1.足付きのものは、「燃やせないごみ」として出してください。2.板のみのものは、「燃やせるごみ」として出してください",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
},
{
"oid": 5,
"item": "アクセサリー類",
"synonym": "アクセサリー類/アクセサリー/あくせさりー/アクセサリ",
"answer": "燃やせないごみ",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
},
{
"oid": 6,
"item": "アコーディオン",
"synonym": "アコーディオン/あこーでぃおん",
"answer": "燃やせないごみ",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
},
{
"oid": 7,
"item": "アタッシェケース",
"synonym": "アタッシェケース・アタッシュケース/アタッシュケース/アタッシェケース",
"answer": "燃やせないごみ",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
},
{
"oid": 8,
"item": "厚紙",
"synonym": "厚紙/あつがみ/あつかみ",
"answer": "古紙類 ※雑誌と一緒に束ねて出してください",
"label1": "",
"url1": "",
"label2": "",
"url2": "",
"label3": "",
"url3": "",
"label4": "",
"url4": ""
}
]
}
itemとanswerを要素とするクラスをGarbageクラスとしてGarbageクラスのリストを作成します。
こちらのケースでもJson.NETの場合は必要なデータのみを直感的に持ってこれているのが分かっていていいですね。反対に、Json Utilityの場合は2つのクラスを作ってあげないと必要なデータを持ってくることができません。
では、実行して処理結果を見てみましょう。ケース1と同じように片方ずつ実行しています。
Json.NET

Json Utility

| JObject.Parse(Json.NET) | JsonUtility.FromJson(Json Utility) | |
|---|---|---|
| 速度(別メソッド呼び出し込み) | 26.92ms | 0.32ms |
| GC Alloc | 88.5KB | 2.1KB |
ケース1に比べてかなりの差ができました。やはりUnityではJson Utilityを使った方がパフォーマンス的に良いということですね。
Jsonデシリアライズまとめ
いわゆる一長一短ってやつですね。リソースが限られている時などはJson Utilityを積極的に使うべきで、そうでもない時はJson.NETを使ってもいいでしょう。
...とは言いつつも、Json Utilityの性能は素晴らしいですね。今後はUnityではJson Utilityを使っていきたくなってしまいます。
というわけで、Json.NETの使い方を残しておこうと記事を書いていたら、思いがけずJson Utilityのハイパフォーマンス性があらわになってしまったという記事でした(笑)
参考
JSON Utility
https://qiita.com/sea_mountain/items/6513b330983ffa003959
https://docs.unity3d.com/ja/2017.4/Manual/JSONSerialization.html
JSON.net
https://www.newtonsoft.com/json/help/html/Introduction.htm
https://www.newtonsoft.com/json/help/html/SerializingJSONFragments.htm
DateTimeカスタム書式設定
https://docs.microsoft.com/ja-jp/dotnet/standard/base-types/custom-date-and-time-format-strings