OUCC

BLOG

記事一覧 タグ一覧

C# のJsonSerializerの速度比較

投稿日:

この記事は OUCC Advent Calendar 2023 の17日目の記事です。前回はぐれいしゃさんによる CTfとは?Ghidraをつかったreversing入門 でした。

C#のJsonSerializerにはMicrosoft製の高速な System.Text.Json と昔からある Newtonsoft.Json があります。.NET8 ではどれくらいの速度差があるのか検証してみました。

検証方法

検証環境は以下のとおりです。

BenchmarkDotNet v0.13.7, Windows 11 (10.0.22631.2861)
12th Gen Intel Core i7-12700F, 1 CPU, 20 logical and 12 physical cores
.NET SDK 8.0.100
  [Host]     : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2 [AttachedDebugger]
  DefaultJob : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2

JSONは #スキーマ のとおりにJSON Generatorで作りました。

条件は次の2×5通りです。Web API用の設定で変換しました。

シリアライズ/デシリアライズするオブジェクトの形

  • Object : オブジェクト単体
  • Array : オブジェクトを200個並べた配列

使用したパターン

  • Newtonsoft.Json.JsonConvert
  • System.Text.Json.JsonSerializer (コード生成なし, UTF16文字列)
  • System.Text.Json.JsonSerializer (コード生成なし, UTF8文字列)
  • System.Text.Json.JsonSerializer (コード生成あり, UTF16文字列)
  • System.Text.Json.JsonSerializer (コード生成あり, UTF8文字列)

計測結果

計測結果は次のようになりました。

デシリアライズ

MethodMeanGen0Gen1Gen2Allocated
DeserializeArray_Newtonsoft1,171.047 μs95.703133.2031-1240.29 KB
DeserializeArray_System_Normal697.791 μs49.804719.5313-637.54 KB
DeserializeArray_System_Generated716.601 μs47.851623.4375-622.35 KB
DeserializeArray_System_Utf8_Normal672.896 μs49.804719.5313-637.54 KB
DeserializeArray_System_Utf8_Generated679.512 μs47.851623.4375-622.36 KB
DeserializeObject_Newtonsoft5.281 μs0.81630.0153-10.5 KB
DeserializeObject_System_Normal2.808 μs0.2403--3.09 KB
DeserializeObject_System_Generated2.983 μs0.2365--3.02 KB
DeserializeObject_System_Utf8_Normal2.733 μs0.2403--3.09 KB

シリアライズ

MethodMeanGen0Gen1Gen2Allocated
SerializeArray_Newtonsoft749.902 μs124.0234124.0234124.0234992.24 KB
SerializeArray_System_Normal470.920 μs124.5117124.5117124.5117436.04 KB
SerializeArray_System_Generated476.420 μs124.5117124.5117124.5117436.04 KB
SerializeArray_System_Utf8_Normal394.480 μs66.406366.406366.4063222.88 KB
SerializeArray_System_Utf8_Generated400.312 μs66.406366.406366.4063222.88 KB
SerializeObject_Newtonsoft2.688 μs0.47680.0038-6.12 KB
SerializeObject_System_Normal1.373 μs0.1659--2.13 KB
SerializeObject_System_Generated1.405 μs0.1659--2.13 KB
SerializeObject_System_Utf8_Normal1.454 μs0.0973--1.26 KB
SerializeObject_System_Utf8_Generated1.457 μs0.0973--1.26 KB

結論

予想通り System.Text.Json は Newtonsoft よりも大幅に上回る速さでした。

一方でコード生成では速度はむしろ下がっており、AOTでコード生成を使わざるを得ないというとき以外は使わないほうが良いという結果になりました。

UTF8文字列のほうが少しだけ速度が大きい理由は System.Text.Json 内部でUTF8で処理されているからだと思われます。(参考:.NET Source Browser)

スキーマ

今回使用したスキーマは次のとおりです。ただし、enumstringへ変換しています。

{
  "id": "657d1ea66512f54f1c7480e7",
  "index": 0,
  "guid": "86649c5d-28f8-469a-96af-ab5e21d5c1da",
  "isActive": true,
  "balance": 1787.06,
  "picture": "http://placehold.it/32x32",
  "age": 30,
  "eyeColor": "blue",
  "name": "Irene Roberts",
  "gender": "female",
  "company": "KOFFEE",
  "email": "ireneroberts@koffee.com",
  "phone": "+1 (988) 512-2759",
  "address": "762 Fillmore Avenue, Winesburg, Texas, 2121",
  "about": "Ex aliquip quis nisi exercitation ipsum veniam. Mollit commodo veniam nisi pariatur. Deserunt id commodo aliquip id. Ea qui qui fugiat do quis ut dolor qui nisi et quis.\r\n",
  "registered": "2022-08-19T09:28:47-09:00",
  "latitude": 7.093724,
  "longitude": 85.030829,
  "tags": [
    "ea",
    "nulla",
    "est",
    "duis",
    "dolor",
    "reprehenderit",
    "cillum"
  ],
  "friends": [
    {
      "id": 0,
      "name": "Sparks Good"
    },
    {
      "id": 1,
      "name": "Leah Gentry"
    },
    {
      "id": 2,
      "name": "Calderon Moran"
    }
  ],
  "greeting": "Hello, Irene Roberts! You have 7 unread messages.",
  "favoriteFruit": "apple"
}
public record Person(
    string Id,
    int Index,
    Guid Guid,
    bool IsActive,
    double Balance,
    string Picture,
    int Age,
    EyeColor EyeColor,
    string Name,
    Gender Gender,
    string Company,
    string Email,
    string Phone,
    string Address,
    string About,
    DateTimeOffset Registered,
    double Latitude,
    double Longitude,
    string[] Tags,
    Person.Friend[] Friends,
    string Greeting,
    string FavoriteFruit)
{
    public record Friend(
        int Id,
        string Name);
}
public enum EyeColor
{
    Blue,
    Brown,
    Green,
}

public enum Gender
{
    Female,
    Male,
    Other,
}