この記事は 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文字列)
計測結果
計測結果は次のようになりました。
デシリアライズ
Method | Mean | Gen0 | Gen1 | Gen2 | Allocated |
---|---|---|---|---|---|
DeserializeArray_Newtonsoft | 1,171.047 μs | 95.7031 | 33.2031 | - | 1240.29 KB |
DeserializeArray_System_Normal | 697.791 μs | 49.8047 | 19.5313 | - | 637.54 KB |
DeserializeArray_System_Generated | 716.601 μs | 47.8516 | 23.4375 | - | 622.35 KB |
DeserializeArray_System_Utf8_Normal | 672.896 μs | 49.8047 | 19.5313 | - | 637.54 KB |
DeserializeArray_System_Utf8_Generated | 679.512 μs | 47.8516 | 23.4375 | - | 622.36 KB |
DeserializeObject_Newtonsoft | 5.281 μs | 0.8163 | 0.0153 | - | 10.5 KB |
DeserializeObject_System_Normal | 2.808 μs | 0.2403 | - | - | 3.09 KB |
DeserializeObject_System_Generated | 2.983 μs | 0.2365 | - | - | 3.02 KB |
DeserializeObject_System_Utf8_Normal | 2.733 μs | 0.2403 | - | - | 3.09 KB |
シリアライズ
Method | Mean | Gen0 | Gen1 | Gen2 | Allocated |
---|---|---|---|---|---|
SerializeArray_Newtonsoft | 749.902 μs | 124.0234 | 124.0234 | 124.0234 | 992.24 KB |
SerializeArray_System_Normal | 470.920 μs | 124.5117 | 124.5117 | 124.5117 | 436.04 KB |
SerializeArray_System_Generated | 476.420 μs | 124.5117 | 124.5117 | 124.5117 | 436.04 KB |
SerializeArray_System_Utf8_Normal | 394.480 μs | 66.4063 | 66.4063 | 66.4063 | 222.88 KB |
SerializeArray_System_Utf8_Generated | 400.312 μs | 66.4063 | 66.4063 | 66.4063 | 222.88 KB |
SerializeObject_Newtonsoft | 2.688 μs | 0.4768 | 0.0038 | - | 6.12 KB |
SerializeObject_System_Normal | 1.373 μs | 0.1659 | - | - | 2.13 KB |
SerializeObject_System_Generated | 1.405 μs | 0.1659 | - | - | 2.13 KB |
SerializeObject_System_Utf8_Normal | 1.454 μs | 0.0973 | - | - | 1.26 KB |
SerializeObject_System_Utf8_Generated | 1.457 μs | 0.0973 | - | - | 1.26 KB |
結論
予想通り System.Text.Json は Newtonsoft よりも大幅に上回る速さでした。
一方でコード生成では速度はむしろ下がっており、AOTでコード生成を使わざるを得ないというとき以外は使わないほうが良いという結果になりました。
UTF8文字列のほうが少しだけ速度が大きい理由は System.Text.Json 内部でUTF8で処理されているからだと思われます。(参考:.NET Source Browser)
スキーマ
今回使用したスキーマは次のとおりです。ただし、enum
はstring
へ変換しています。
{
"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,
}