.NET9 实现 JSON 序列化和反序列化(Newtonsoft.Json System.Text.Json)性能测试
为了在 .NET 9
平台上对比 Newtonsoft.Json
和 System.Text.Json
的序列化与反序列化的性能,我们可以使用 BenchmarkDotNet
来进行压测。
目录
- 1. 项目准备
- 2. 基准测试环境
- 3. 性能对比
- a. 对象级别的序列化(Object-Level Serialization)
- b. 对象级别的反序列化(Object-Level Deserialization)
- c. API 响应级别的序列化(ApiResponse-Level Serialization)
- d. API 响应级别的反序列化(ApiResponse-Level Deserialization)
- 4. 总体结论
- 5. 注意事项
此处为了方便对比,我会创建两个类:
JsonOperations.cs
:JSON
序列化和反序列化操作类;JsonBenchmark.cs
:序列化操作基准测试类;
以下是一个完整的示例代码,它将帮助你创建一个基准测试项目来比较这两种 JSON
序列化库的性能。
1. 项目准备
首先,请确保你的项目中已经添加了相应的 NuGet
包引用:
Newtonsoft.Json
(版本13.0.3
)
dotnet add package Newtonsoft.Json --version 13.0.3
System.Text.Json
(版本9.0.6
)
dotnet add package System.Text.Json --version 9.0.6
- 添加
BenchmarkDotNet
基准测试包
dotnet add package Datadog.Trace.BenchmarkDotNet --version 2.61.0
控制台 .csproj
项目结构如下:
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net9.0</TargetFramework><ImplicitUsings>enable</ImplicitUsings><Nullable>enable</Nullable><PublishAot>true</PublishAot><InvariantGlobalization>true</InvariantGlobalization></PropertyGroup><ItemGroup><PackageReference Include="Datadog.Trace.BenchmarkDotNet" Version="2.61.0" /><PackageReference Include="Newtonsoft.Json" Version="13.0.3" /><PackageReference Include="System.Text.Json" Version="9.0.6" /></ItemGroup></Project>
JsonOperations
// ========================================
// JsonOperations 序列化和反序列化操作类
// ========================================using System.Text.Json;namespace BenchmarkTest.examples.Json;internal class JsonOperations
{public string SerializeWithSystemTextJson(object obj){return JsonSerializer.Serialize(obj);}public T DeserializeWithSystemTextJson<T>(string json){return JsonSerializer.Deserialize<T>(json);}public string SerializeWithNewtonsoftJson(object obj){return Newtonsoft.Json.JsonConvert.SerializeObject(obj);}public T DeserializeWithNewtonsoftJson<T>(string json){return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(json);}
}
JsonBenchmark
// ===========================================
// JsonBenchmark 序列化和反序列化操作基准测试类
// ===========================================using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Running;
using Datadog.Trace.BenchmarkDotNet;namespace BenchmarkTest.examples.Json;[DatadogDiagnoser]
[MemoryDiagnoser]
public class JsonBenchmark
{private readonly JsonOperations _jsonOps = new();private static readonly object _testObject = new { Name = "Test", Value = 123 };private readonly ApiResponse _apiResponse = new(true, 200, "ok", _testObject);private string _systemTextJsonSerializedObject = string.Empty;private string _newtonsoftJsonSerializedObject = string.Empty;private string _systemTextJsonSerializedApiResponse = string.Empty;private string _newtonsoftJsonSerializedApiResponse = string.Empty;[GlobalSetup]public void Setup(){_systemTextJsonSerializedObject = _jsonOps.SerializeWithSystemTextJson(_testObject);_newtonsoftJsonSerializedObject = _jsonOps.SerializeWithNewtonsoftJson(_testObject);_systemTextJsonSerializedApiResponse = _jsonOps.SerializeWithSystemTextJson(_apiResponse);_newtonsoftJsonSerializedApiResponse = _jsonOps.SerializeWithNewtonsoftJson(_apiResponse);}[Benchmark]public string SystemTextJsonSerialize_Object() => _jsonOps.SerializeWithSystemTextJson(_testObject);[Benchmark]public object SystemTextJsonDeserialize_Object() => _jsonOps.DeserializeWithSystemTextJson<object>(_systemTextJsonSerializedObject);[Benchmark]public string NewtonsoftJsonSerialize_Object() => _jsonOps.SerializeWithNewtonsoftJson(_testObject);[Benchmark]public object NewtonsoftJsonDeserialize_Object() => _jsonOps.DeserializeWithNewtonsoftJson<object>(_newtonsoftJsonSerializedObject);[Benchmark]public string SystemTextJsonSerialize_ApiResponse() => _jsonOps.SerializeWithSystemTextJson(_apiResponse);[Benchmark]public object SystemTextJsonDeserialize_ApiResponse() => _jsonOps.DeserializeWithSystemTextJson<ApiResponse>(_systemTextJsonSerializedApiResponse);[Benchmark]public string NewtonsoftJsonSerialize_ApiResponse() => _jsonOps.SerializeWithNewtonsoftJson(_apiResponse);[Benchmark]public object NewtonsoftJsonDeserialize_ApiResponse() => _jsonOps.DeserializeWithNewtonsoftJson<ApiResponse>(_newtonsoftJsonSerializedApiResponse);public static void Run(IConfig config){var summary = BenchmarkRunner.Run<JsonBenchmark>(config);Console.WriteLine(summary);}
}// 模拟强类型对象数据
public record ApiResponse(bool Success, int Code, string Message, object Data);
- 在
Program.cs
中运行基准测试
using BenchmarkDotNet.Configs;
using BenchmarkTest.examples.Json;
using Datadog.Trace.BenchmarkDotNet;Console.WriteLine("Hello, BenchmarkDotNetTest!");var config = DefaultConfig.Instance.WithDatadog();
JsonBenchmark.Run(config);
- 运行测试
在项目根目录,使用 pwsh
终端输入命令:
dotnet run -c Release
输出信息:
以下是对 BenchmarkDotNet
测试结果的详细分析:
根据提供的测试信息,我们可以从以下几个方面对 Newtonsoft.Json
和 System.Text.Json
的序列化与反序列化的性能进行详细分析:
2. 基准测试环境
- BenchmarkDotNet 版本:
v0.13.2
- 操作系统:
Windows 11 (10.0.26100.4484)
- .NET SDK:
9.0.301
- 运行时:
.NET 9.0.6 (9.0.625.26613)
,使用X64 AOT AVX2
指令集
这些信息表明,基准测试是在一个较为先进的硬件和软件环境中进行的,能够提供可靠的性能评估。
3. 性能对比
a. 对象级别的序列化(Object-Level Serialization)
方法 | 平均耗时 (Mean) | 内存分配 (Allocated) |
---|---|---|
SystemTextJsonSerialize_Object | 296.8 ns | 80 B |
NewtonsoftJsonSerialize_Object | 502.5 ns | 1392 B |
分析:
System.Text.Json
在序列化操作中表现明显优于Newtonsoft.Json
。它的平均耗时仅为 296.8 纳秒,而Newtonsoft.Json
需要 502.5 纳秒。- 在内存分配方面,
System.Text.Json
分配了 80 字节,而Newtonsoft.Json
分配了 1392 字节。这说明System.Text.Json
在内存管理上更加高效。
b. 对象级别的反序列化(Object-Level Deserialization)
方法 | 平均耗时 (Mean) | 内存分配 (Allocated) |
---|---|---|
SystemTextJsonDeserialize_Object | 611.2 ns | 256 B |
NewtonsoftJsonDeserialize_Object | 1,299.3 ns | 3624 B |
分析:
System.Text.Json
的反序列化操作同样优于Newtonsoft.Json
,其平均耗时为 611.2 纳秒,而Newtonsoft.Json
需要 1299.3 纳秒。- 内存分配方面,
System.Text.Json
分配了 256 字节,而Newtonsoft.Json
分配了 3624 字节。这表明System.Text.Json
在反序列化时也具有更低的资源消耗。
c. API 响应级别的序列化(ApiResponse-Level Serialization)
方法 | 平均耗时 (Mean) | 内存分配 (Allocated) |
---|---|---|
SystemTextJsonSerialize_ApiResponse | 758.4 ns | 488 B |
NewtonsoftJsonSerialize_ApiResponse | 954.4 ns | 1688 B |
分析:
- 在处理更复杂的结构(如 API 响应)时,
System.Text.Json
仍然保持优势。它的平均耗时为 758.4 纳秒,而Newtonsoft.Json
需要 954.4 纳秒。 - 内存分配方面,
System.Text.Json
分配了 488 字节,而Newtonsoft.Json
分配了 1688 字节。
d. API 响应级别的反序列化(ApiResponse-Level Deserialization)
方法 | 平均耗时 (Mean) | 内存分配 (Allocated) |
---|---|---|
SystemTextJsonDeserialize_ApiResponse | 1,145.0 ns | 424 B |
NewtonsoftJsonDeserialize_ApiResponse | 2,476.1 ns | 4272 B |
分析:
- 对于复杂结构的反序列化操作,
System.Text.Json
的平均耗时为 1145.0 纳秒,而Newtonsoft.Json
需要 2476.1 纳秒。 - 内存分配方面,
System.Text.Json
分配了 424 字节,而Newtonsoft.Json
分配了 4272 字节。这表明System.Text.Json
在处理复杂结构时依然具有显著的性能优势。
4. 总体结论
- 性能优势:
System.Text.Json
在所有测试场景中都表现出比Newtonsoft.Json
更高的性能,无论是简单的对象级别还是复杂的API
响应级别。 - 内存效率:
System.Text.Json
在内存分配方面远低于Newtonsoft.Json
,这使得它在高并发或资源受限的环境中更具优势。 - 适用性建议:如果你的应用程序需要高效的
JSON
序列化/反序列化操作,并且不需要Newtonsoft.Json
提供的一些高级功能(如支持更多类型、更灵活的配置等),那么推荐使用System.Text.Json
。
5. 注意事项
- 异常值(Outliers):在某些测试中发现了异常值并进行了剔除处理,例如
SystemTextJsonDeserialize_Object
中有 3 个异常值被移除。这些异常值可能会影响最终结果的准确性,但基准测试工具已经自动处理了这些问题。 - 统计指标:测试报告中的
Mean
表示平均耗时,Error
和StdDev
分别表示误差范围和标准差,它们用于衡量测量的可靠性。较小的标准差意味着测试结果更加稳定。
通过上述分析,可以看出 System.Text.Json
是当前 .NET 9
平台上更优的选择,特别是在性能和内存效率方面。