ゆべねこの足跡

IT系のはなしを残しておく場所です

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の最新バージョンに比べて少し古いバージョンを使っているようなので、今回は公式の最新リリースを使っていきます。

github.com

2019年11月1日時点では最新バージョンは 12.0.2 でした。上記ページからJson120r2.zipをダウンロードし、解凍した後Json120r2/Bin/net45以下にあるNewtonsoft.Json.dllをUnityプロジェクトのAssets/Plugins以下に配置します。

ケースその1

以下のデータからtype1timesを抽出して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 f:id:yubeshineko:20191102164121p:plain

Json Utility f:id:yubeshineko:20191102164130p:plain

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オブジェクトの配列中のitemanswerの要素を持つクラスのリストを作ります。ちなみに、このデータはこちらのものを改変して作りました。

{
    "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": ""
        }
    ]
}

itemanswerを要素とするクラスをGarbageクラスとしてGarbageクラスのリストを作成します。

こちらのケースでもJson.NETの場合は必要なデータのみを直感的に持ってこれているのが分かっていていいですね。反対に、Json Utilityの場合は2つのクラスを作ってあげないと必要なデータを持ってくることができません。

では、実行して処理結果を見てみましょう。ケース1と同じように片方ずつ実行しています。

Json.NET f:id:yubeshineko:20191102163144p:plain

Json Utility f:id:yubeshineko:20191102163258p:plain

JObject.Parse(Json.NET) JsonUtility.FromJson(Json Utility)
速度(別メソッド呼び出し込み) 26.92ms 0.32ms
GC Alloc 88.5KB 2.1KB

ケース1に比べてかなりの差ができました。やはりUnityではJson Utilityを使った方がパフォーマンス的に良いということですね。

Jsonシリアライズまとめ

  • Json.NET

    • + 必要な部分のみを直感的に引っ張ってこれる
    • Jsonの様々な処理を行える
    • Json Utilityに比べメモリ使用量が多く、処理も時間がかかる
  • Json Utility

    • − 必要な部分のみ引っ張ってきたいときもわざわざクラスを用意する必要がある
    • − 使える機能がJson.NETに比べて少ない
    • Json.NETに比べメモリ使用量が少なく、処理も高速

いわゆる一長一短ってやつですね。リソースが限られている時などは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