.NET Performance Analysis: Newtonsoft.Json vs System.Text.Json in .NET 9
Today, I want to talk about something that’s been on my mind lately - JSON serialization in .NET. As a passionate developer, I’m always curious about the best ways to solve problems, and JSON serialization is no exception.
Recently, I came across an article by Trevor McCubbin that compared the performance of System.Text.Json and Newtonsoft.Json in .NET 8. I was intrigued by the results, and it got me thinking - how do these two popular JSON serialization libraries stack up against each other in .NET 9?
In this article, I’ll share my findings and provide some insights into the performance and features of both System.Text.Json and Newtonsoft.Json.
Benchmark Setup
To accurately compare the performance of System.Text.Json and Newtonsoft.Json in JSON serialization, I’ll be focusing on two main use cases:
Serialization and Deserialization of a Single Large Dataset: This will provide insights into how each library handles bulk data. Serialization and Deserialization of Many Small Datasets: This will showcase how each library performs when dealing with a large number of smaller payloads. To generate diverse test data, I’ll be utilizing the Bogus NuGet package to generate random users with unique identities. This will help us evaluate how each library handles different types of data.
[GlobalSetup]
public void GlobalSetup()
{
var faker = new Faker<Person>()
.RuleFor(c => c.Name, f => f.Name.FullName())
.RuleFor(c => c.Age, f => f.Random.Int(1, 100))
.RuleFor(c => c.DateOfBirth, f => f.Date.Recent())
.RuleFor(c => c.IsMarried, f => f.Random.Bool())
.RuleFor(c => c.Children, f => f.Lorem.Words(f.Random.Int(1, 5)));
persons = faker.Generate(Count);
personsJson = System.Text.Json.JsonSerializer.Serialize(persons);
personListJson = persons.Select(c => System.Text.Json.JsonSerializer.Serialize(c)).ToList();
}
Performance
Deserialize Big Data
In this benchmark, we will compare deserialization performance of both approaches using a single large object.
[BenchmarkCategory("DeserializeBigData"), Benchmark]
public void JsonSerializer_Deserialize_BigData()
{
_ = System.Text.Json.JsonSerializer.Deserialize<List<Person>>(personsJson);
}
[BenchmarkCategory("DeserializeBigData"), Benchmark(Baseline = true)]
public void JsonConvert_Deserialize_BigData()
{
_ = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Person>>(personsJson);
}
Results
| Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
|---|---|---|---|---|---|---|---|---|
| JsonSerializer_Deserialize_BigData | 10000 | 20.88 ms | 0.394 ms | 0.368 ms | 0.78 | 0.02 | 3.72 MB | 0.85 |
| JsonConvert_Deserialize_BigData | 10000 | 26.78 ms | 0.535 ms | 0.657 ms | 1.00 | 0.03 | 4.39 MB | 1.00 |
Just like in the .NET 8 analysis, System.Text.Json is the clear winner when it comes to deserialization performance
Deserialize Small Data Objects
In this scenario, we test the deserialization of multiple small JSON objects.
[BenchmarkCategory("DeserializeSmallData"), Benchmark]
public void JsonSerializer_Deserialize_SmallData()
{
foreach (var person in personListJson)
{
_ = System.Text.Json.JsonSerializer.Deserialize<Person>(person);
}
}
[BenchmarkCategory("DeserializeSmallData"), Benchmark(Baseline = true)]
public void JsonConvert_Deserialize_SmallData()
{
foreach (var person in personListJson)
{
_ = Newtonsoft.Json.JsonConvert.DeserializeObject<Person>(person);
}
}
Results
| Method | Count | Mean | Error | StdDev | Ratio | Allocated | Alloc Ratio |
|---|---|---|---|---|---|---|---|
| JsonSerializer_Deserialize_SmallData | 10000 | 11.36 ms | 0.122 ms | 0.115 ms | 0.63 | 7.96 MB | 0.26 |
| JsonConvert_Deserialize_SmallData | 10000 | 18.14 ms | 0.222 ms | 0.197 ms | 1.00 | 30.55 MB | 1.00 |
System.Text.Json once more demonstrates its superiority, outperforming Newtonsoft.Json in both speed and memory efficiency. Notably, it achieves this while using less than half the memory.
Serialize Big Data Object
Now lets look into serialization of big data object
[BenchmarkCategory("SerializeBigData"), Benchmark]
public void JsonSerializer_Serialize_BigData()
{
_ = System.Text.Json.JsonSerializer.Serialize(persons);
}
[BenchmarkCategory("SerializeBigData"), Benchmark(Baseline = true)]
public void JsonConvert_Serialize_BigData()
{
_ = Newtonsoft.Json.JsonConvert.SerializeObject(persons);
}
Results
| Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
|---|---|---|---|---|---|---|---|---|
| JsonSerializer_Serialize_BigData | 10000 | 7.784 ms | 0.0830 ms | 0.0736 ms | 0.66 | 0.02 | 2.69 MB | 0.42 |
| JsonConvert_Serialize_BigData | 10000 | 11.788 ms | 0.2297 ms | 0.4022 ms | 1.00 | 0.05 | 6.4 MB | 1.00 |
Yet again, System.Text.Json performs better than Newtonsoft.Json in both execution time and memory.
Serialise Small Data Object
This is a common scenario where we serialize several small data objects to JSON.
[BenchmarkCategory("SerializeSmallData"), Benchmark]
public void JsonSerializer_Serialize_SmallData()
{
foreach (var person in persons)
{
_ = System.Text.Json.JsonSerializer.Serialize(person);
}
}
[BenchmarkCategory("SerializeSmallData"), Benchmark(Baseline = true)]
public void JsonConvert_Serialize_SmallData()
{
foreach (var person in persons)
{
_ = Newtonsoft.Json.JsonConvert.SerializeObject(person);
}
}
Results
| Method | Count | Mean | Error | StdDev | Ratio | Allocated | Alloc Ratio |
|---|---|---|---|---|---|---|---|
| JsonSerializer_Serialize_SmallData | 10000 | 7.917 ms | 0.0683 ms | 0.0605 ms | 0.72 | 5.89 MB | 0.33 |
| JsonConvert_Serialize_SmallData | 10000 | 10.990 ms | 0.0766 ms | 0.0717 ms | 1.00 | 17.63 MB | 1.00 |
And there are no surprises. System.Text.Json still outperforms Newtonsoft.Json in serializing multiple small data objects.
Features
While System.Text.Json is a more lightweight and performant option, Newtonsoft.Json has some features that may be important to your application. Here are a few examples:
-
Serialization of complex objects:
Newtonsoft.Jsonhas better support for serializing complex objects, such as those with circular references. -
Custom converters:
Newtonsoft.Jsonhas a more extensive set of custom converters, which can be useful for handling specific serialization scenarios. -
LINQ to JSON:
Newtonsoft.Jsonhas a LINQ to JSON API, which allows you to query and manipulate JSON data using LINQ.
However, System.Text.Json has some features that are not available in Newtonsoft.Json, such as:
-
Async serialization:
System.Text.Jsonhas built-in support for async serialization, which can improve performance in certain scenarios. -
Streaming:
System.Text.Jsonhas built-in support for streaming, which can be useful for handling large JSON payloads.
Conclusion
In conclusion, System.Text.Json is a more performant and lightweight option for working with JSON in .NET 9. While Newtonsoft.Json has some features that may be important to your application.
You can download this sample code from github https://github.com/updateaman/JsonSerializerVsJsonConvert/blob/main/Program.cs
tags: json - parsing - performance