c# System.Text.Json 和 Newtonsoft.Json 在高并发下的性能对比

来源:这里教程网 时间:2026-02-21 17:41:21 作者:

System.Text.Json 序列化吞吐量明显更高,但默认不支持循环引用和某些类型

在 Web API 或微服务高频请求场景下,

System.Text.Json
的序列化/反序列化吞吐量通常比
Newtonsoft.Json
高 1.5–2.5 倍,尤其在小对象(如 DTO)密集读写时。这源于它基于
Span<byte></byte>
和零分配设计,避免了大量字符串拼接与中间
StringBuilder
缓冲区。但它的默认行为更“严格”:不处理对象图中的循环引用、不支持
DataTable
ExpandoObject
、对
Dictionary<string object></string>
的键类型要求更死板。

Newtonsoft.Json 在高并发下 GC 压力更大,尤其使用默认设置时

典型表现是

Gen 0
GC 频率陡增,甚至触发
Gen 1
,导致请求延迟毛刺。原因包括:
JToken
层级结构堆分配多、默认启用
TypeNameHandling
时写入额外元数据、
JsonConvert.SerializeObject
每次调用都可能新建内部缓存上下文(除非显式复用
JsonSerializer
实例)。实操建议:

始终复用
JsonSerializer
实例(而非反复调用静态
JsonConvert
方法)
禁用
TypeNameHandling
,除非真需要反序列化为运行时未知类型
对已知结构的 JSON,优先用
JObject.Parse()
+ 显式属性访问,而非
DeserializeObject<t>()</t>

高并发下
System.Text.Json
的坑:自定义转换器 + 同步锁易成瓶颈

当需要兼容旧系统(如日期格式为

"yyyy-MM-dd"
)、或处理
DBNull
KeyValuePair
等特殊值时,常需注册自定义
JsonConverter<t></t>
。若转换器内部用了
lock
Monitor.Enter
或非线程安全的静态缓存(如
ConcurrentDictionary
误用为普通
Dictionary
),会直接拖垮吞吐。示例错误写法:

public class BadDateConverter : JsonConverter<DateTime>
{
    private static readonly Dictionary<string, DateTime> _cache = new(); // 非线程安全!
    public override DateTime Read(...){ ... }
    public override void Write(...){ ... }
}

正确做法是:用

ConcurrentDictionary
、避免锁、或把缓存逻辑移到上层(如 ASP.NET Core 的
HttpContext.Items
)。

真实压测中,差异往往卡在配置而非底层库

很多团队测出“Newtonsoft 更快”,实际是因为没关

System.Text.Json
的默认验证(如
PropertyNameCaseInsensitive = true
开销显著)或没预热
JsonSerializerOptions
。关键配置对比:

System.Text.Json
:必须提前构造单例
JsonSerializerOptions
,设
PropertyNameCaseInsensitive = false
、禁用
WriteIndented
、注册转换器用
options.Converters.Add(...)
而非每次新建
Newtonsoft.Json
:用
JsonSerializer.Create(settings)
构建实例,禁用
Formatting.Indented
ReferenceLoopHandling
TypeNameHandling
两者都应关闭日志/诊断(如 ASP.NET Core 中禁用
Microsoft.AspNetCore.Mvc.Formatters.JsonOutputFormatter
的详细错误)

真正决定高并发表现的,经常是这些配置是否被正确固化,而不是选哪个库本身。

相关推荐