为什么 JsonConvert 比 ASP.NET Core 的内置 Json Formatter 更快?
Why JsonConvert is Faster than ASP.NET Core's Built-In Json Formatter?
我了解到 ASP.NET Core 使用 Newtonsoft.Json 9.0.1 作为其内置的 JSON 格式化程序 (Microsoft.AspNetCore.JsonPatch)。但是,我仍然没有弄清楚是什么导致了这两个代码之间的性能差异:
使用内置 JSON 格式化程序 (Newtonsoft.Json 9.0.1)
[Produces("application/json")]
[Route("api/BuiltIn")]
public class BuiltInController : Controller
{
private static readonly BufferBlock<ParentModel> Block = new BufferBlock<ParentModel>();
// GET: api/BuiltIn
[HttpGet]
public ParentModel Get()
{
if (!Block.TryReceive(out ParentModel model)) return null;
return model;
}
// POST: api/BuiltIn
[HttpPost]
public bool Post([FromBody]ParentModel model)
{
if (model == null) return false;
return Block.Post(model);
}
}
Results (10k requests):
POST - 64 minutes 19 seconds, GET - 57 minutes 8 seconds
使用 JsonConvert(Newtonsoft.Json 9.0.1 在 AspNetCore 中引用)
[Produces("application/json")]
[Route("api/JsonConvert")]
public class JsonConvertController : Controller
{
private static readonly BufferBlock<ParentModel> Block = new BufferBlock<ParentModel>();
// GET: api/JsonConvert
[HttpGet]
public ContentResult Get()
{
if (!Block.TryReceive(out ParentModel model)) return Content(null);
return Content(JsonConvert.SerializeObject(model));
}
// POST: api/JsonConvert
[HttpPost]
public bool Post()
{
using (var reader = new StreamReader(Request.Body))
{
var request = reader.ReadToEnd();
if (request == null) return false;
var model = JsonConvert.DeserializeObject<ParentModel>(request);
return Block.Post(model);
}
}
}
Results (10k requests):
POST - 63 minutes 47 seconds, GET - 56 minutes 18 seconds
无论我测试了多少请求,直接使用 JsonConvert 的性能都稍好一些(大约 1%)。造成这种性能差异的原因可能是什么?
除非您对其进行分析,否则我们无法告诉您。
但是你应该忽略这个小区别,这很可能是由于当你使用 Content(...)
或 Ok(...)
辅助方法时触发了额外的 GC,你也总是实例化一个 ContentResult
and/or OkObjectResult
(参见 BaseController.cs source),当直接返回模型时,这些可能会被重用。
[NonAction]
public virtual OkObjectResult Ok(object value)
{
return new OkObjectResult(value);
}
您的测试也很可能是错误的,因为 ASP.NET 核心能够很好地每秒处理 200k 个请求(参见 TechEmpower Benchmark, Round 14)或者您没有使用 http 管道,而不是 运行 基准测试工具和 ASP.NET 在不同物理计算机上的应用等
更新
另请注意,使用 public bool Post()
的第二个测试不会调用模型绑定器,但是 public bool Post([FromBody]ParentModel model)
会调用。当您将模型作为参数时,ASP.NET Core 必须调用 IModelBinderFactory.CreateBinder
(source) 以获得正确的模型绑定器(即 ComplexTypeModelBinder
和其他取决于您的模型的外观喜欢,喜欢 ArrayModelBinder
、DictionaryModelBinder
、BodyModelBinder
等)。
因此,您的测试所做的是有效地测试 return Content(string)
方法的模型绑定器 and/or 开销(包括 ContentResult
的实例化)和 not JSON.NET 直接与 JSON.NET 由 ASP.NET 核心调用。
随着 .NET Core 3 的发布,JSON 序列化的性能将得到显着提升。
https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/
博客 post 还包含一些指标,概述了您可以期待的改进。
我了解到 ASP.NET Core 使用 Newtonsoft.Json 9.0.1 作为其内置的 JSON 格式化程序 (Microsoft.AspNetCore.JsonPatch)。但是,我仍然没有弄清楚是什么导致了这两个代码之间的性能差异:
使用内置 JSON 格式化程序 (Newtonsoft.Json 9.0.1)
[Produces("application/json")]
[Route("api/BuiltIn")]
public class BuiltInController : Controller
{
private static readonly BufferBlock<ParentModel> Block = new BufferBlock<ParentModel>();
// GET: api/BuiltIn
[HttpGet]
public ParentModel Get()
{
if (!Block.TryReceive(out ParentModel model)) return null;
return model;
}
// POST: api/BuiltIn
[HttpPost]
public bool Post([FromBody]ParentModel model)
{
if (model == null) return false;
return Block.Post(model);
}
}
Results (10k requests):
POST - 64 minutes 19 seconds, GET - 57 minutes 8 seconds
使用 JsonConvert(Newtonsoft.Json 9.0.1 在 AspNetCore 中引用)
[Produces("application/json")]
[Route("api/JsonConvert")]
public class JsonConvertController : Controller
{
private static readonly BufferBlock<ParentModel> Block = new BufferBlock<ParentModel>();
// GET: api/JsonConvert
[HttpGet]
public ContentResult Get()
{
if (!Block.TryReceive(out ParentModel model)) return Content(null);
return Content(JsonConvert.SerializeObject(model));
}
// POST: api/JsonConvert
[HttpPost]
public bool Post()
{
using (var reader = new StreamReader(Request.Body))
{
var request = reader.ReadToEnd();
if (request == null) return false;
var model = JsonConvert.DeserializeObject<ParentModel>(request);
return Block.Post(model);
}
}
}
Results (10k requests):
POST - 63 minutes 47 seconds, GET - 56 minutes 18 seconds
无论我测试了多少请求,直接使用 JsonConvert 的性能都稍好一些(大约 1%)。造成这种性能差异的原因可能是什么?
除非您对其进行分析,否则我们无法告诉您。
但是你应该忽略这个小区别,这很可能是由于当你使用 Content(...)
或 Ok(...)
辅助方法时触发了额外的 GC,你也总是实例化一个 ContentResult
and/or OkObjectResult
(参见 BaseController.cs source),当直接返回模型时,这些可能会被重用。
[NonAction]
public virtual OkObjectResult Ok(object value)
{
return new OkObjectResult(value);
}
您的测试也很可能是错误的,因为 ASP.NET 核心能够很好地每秒处理 200k 个请求(参见 TechEmpower Benchmark, Round 14)或者您没有使用 http 管道,而不是 运行 基准测试工具和 ASP.NET 在不同物理计算机上的应用等
更新
另请注意,使用 public bool Post()
的第二个测试不会调用模型绑定器,但是 public bool Post([FromBody]ParentModel model)
会调用。当您将模型作为参数时,ASP.NET Core 必须调用 IModelBinderFactory.CreateBinder
(source) 以获得正确的模型绑定器(即 ComplexTypeModelBinder
和其他取决于您的模型的外观喜欢,喜欢 ArrayModelBinder
、DictionaryModelBinder
、BodyModelBinder
等)。
因此,您的测试所做的是有效地测试 return Content(string)
方法的模型绑定器 and/or 开销(包括 ContentResult
的实例化)和 not JSON.NET 直接与 JSON.NET 由 ASP.NET 核心调用。
随着 .NET Core 3 的发布,JSON 序列化的性能将得到显着提升。
https://devblogs.microsoft.com/dotnet/try-the-new-system-text-json-apis/
博客 post 还包含一些指标,概述了您可以期待的改进。