Search  
Always will be ready notify the world about expectations as easy as possible: job change page
May 6

.NET performance analysis: Newtonsoft.Json vs System.Text.Json in .NET 8

.NET performance analysis: Newtonsoft.Json vs System.Text.Json in .NET 8
Author:
Source:
Views:
617

Introduction

As a passionate .NET developer, I find myself continuously seeking opportunities to expand my understanding of the .NET ecosystem. In this, my first article ever, I embark on a journey to explore the intricacies of .NET performance, with a specific focus on two prominent JSON frameworks: Newtonsoft.Json and Microsoft’s System.Text.Json. My goal is to share the insights and revelations gained during this exploration with fellow developers who, like me, are keen on deciphering the nuances within our tech ecosystem.

This article is inspired by Tobias Streng’s noteworthy article on .NET 7 performance and I’ve tailored my investigation to align with the latest advancements in .NET 8. Join me on this quest as we uncover the nuances between these two JSON powerhouses and gain a deeper understanding of their performance implications in real-world scenarios.

Original Article: .NET Performance #2: Newtonsoft vs. System.Text.Json by Tobias Streng

Framework Popularity

As of January 27th, 2024, Newtonsoft.Json boasts an impressive record of over 4.2 billion downloads, securing its position as the most downloaded package on NuGet. In contrast, System.Text.Json lags behind with approximately 1.8 billion downloads. Notably, System.Text.Json’s inclusion as a default in the .NET SDK since .NET Core 3.1 significantly contributes to its widespread adoption.

Comparing these numbers to the original .NET 7 article reveals a compelling narrative. At that time, Newtonsoft.Json had accumulated 2.3 billion downloads, signifying an 82.6% increase in download count over the 15-month period. In the same timeframe, System.Text.Json experienced a remarkable growth of 200%, suggesting a faster pace of adoption. However, when examining the sheer download numbers, Newtonsoft.Json added a staggering 1.9 billion downloads in this period — surpassing the total downloads for System.Text.Json since its introduction into the .NET SDK in 2019.

Benchmark Scenarios

To recreate the same scenarios as the original article, we’ll focus on two main use cases:

  1. Serialization and deserialization of a single large dataset.
  2. Serialization and deserialization of many small datasets.

For test data, we will leverage the NuGet package Bogus to generate random users with their own unique identity.

[Params(10000)]
public int Count { get; set; }

private List<User> testUsers =  [ ];

[GlobalSetup]
public void GlobalSetup()
{
    var faker = new Faker<User>().CustomInstantiator(
        f =>
            new User(
            Guid.NewGuid(),
            f.Name.FirstName(),
            f.Name.LastName(),
            f.Name.FullName(),
            f.Internet.UserName(f.Name.FirstName(), f.Name.LastName()),
            f.Internet.Email(f.Name.FirstName(), f.Name.LastName())
            )
    );

    testUsers = faker.Generate(Count);
}

Benchmark Setup

  • Newtonsoft.Json 13.0.3
  • System.Text.Json 8.0.1
  • Bogus 35.4.0
  • BenchmarkDotNet 0.13.12

Serialization Benchmarks

Serialize Big Data Object

In this benchmark, we examine the serialization performance of a single large object using the List<User> data structure. Both frameworks utilize the default ContractResolver.

[Benchmark]
public void NewtonsoftSerializeBigData() =>
    _ = Newtonsoft.Json.JsonConvert.SerializeObject(testUsers);

[Benchmark]
public void MicrosoftSerializeBigData() =>
    _ = System.Text.Json.JsonSerializer.Serialize(testUsers);

Results:

Big Data Method Count Mean Ratio Allocated Alloc Ratio
Newtonsoft 10000 9.415 ms 1.00 8.07 MB 1.00
Microsoft 10000 5.543 ms 1.00 3.42 MB 1.00

The results mirror those found in the .NET 7 analysis, where System.Text.Json outperforms Newtonsoft.Json by over twice the speed. Microsoft’s package also exhibits superior memory efficiency, using less than half the memory compared to Newtonsoft.Json.

Serialize Big Data Object With Custom Json Serializor Settings

In this scenario, we revisit the previous serialization test, introducing a new element: converting the JSON properties to snake case. Note that:

instantiating the ContractResolver more than once can incur a performance hit, so careful consideration is needed.

[Benchmark]
public void NewtonsoftSerializeBigDataWithSettings()
{
    var settings = new Newtonsoft.Json.JsonSerializerSettings()
    {
        Formatting = Newtonsoft.Json.Formatting.Indented,
        ContractResolver = new DefaultContractResolver
        {
            NamingStrategy = new SnakeCaseNamingStrategy()
        }
    };

    _ = Newtonsoft.Json.JsonConvert.SerializeObject(testUsers, settings);
}

[Benchmark]
public void MicrosoftSerializeBigDataWithSettings()
{
    var settings = new JsonSerializerOptions()
    {
        WriteIndented = true,
        PropertyNamingPolicy = new SnakeCasePropertyNamingPolicy()
    };

    _ = System.Text.Json.JsonSerializer.Serialize(testUsers, settings);
}

Results:

Big Data With Settings Method Count Mean Ratio Allocated Alloc Ratio
Newtonsoft 10000 14.093 ms 1.00 10.24 MB 1.00
Microsoft 10000 7.036 ms 1.00 4.48 MB 1.00

The results indicate that both Newtonsoft.Json and Microsoft’s System.Text.Json experience a performance hit and increased memory usage when applying a custom naming policy. However, Newtonsoft.Json shows a more significant increase in mean execution time (4.678 ms) compared to System.Text.Json (1.493 ms), suggesting that Newtonsoft.Json takes approximately 213% more time to execute than Microsoft’s package when applying the same naming policy.

Serialize Many Small Data Objects

This scenario represents a realistic use-case for JSON serialization, closely simulating REST APIs. The benchmark involves looping through the List<User> and serializing each user individually.

[Benchmark]
public void NewtonsoftSerializeIndividualData()
{
    foreach (var user in testUsers)
    {
        _ = Newtonsoft.Json.JsonConvert.SerializeObject(user);
    }
}

[Benchmark]
public void MicrosoftSerializeIndividualData()
{
    foreach (var user in testUsers)
    {
        _ = System.Text.Json.JsonSerializer.Serialize(user);
    }
}

Results:

Individual Data Method Count Mean Ratio Allocated Alloc Ratio
Newtonsoft 10000 7.032 ms 1.00 17.14 MB 1.00
Microsoft 10000 4.870 ms 1.00 3.64 MB 1.00

As observed, Microsoft’s System.Text.Json once again demonstrates faster mean execution time compared to Newtonsoft.Json. Additionally, it is important to note the significant difference in memory allocation between the two packages. Tobias Streng emphasizes the importance of saving heap memory, considering its impact on overall application performance.

“saving heap memory is even more important than the speed, you are seeing here. Heap memory will eventually have to be garbage collected, which will block your entire application from executing”

Deserialization Benchmarks

Deserialize Big Data Object

Now, we’ll shift our focus to deserialization, starting with a benchmark for deserializing one large JSON string into the respective .NET object List<User>.

[Benchmark]
public void NewtonsoftDeserializeBigData() =>
    _ = Newtonsoft.Json.JsonConvert.DeserializeObject<List<User>>(serializedTestUsers);

[Benchmark]
public void MicrosoftDeserializeBigData() =>
    _ = System.Text.Json.JsonSerializer.Deserialize<List<User>>(serializedTestUsers);

Results:

Big Data Method Count Mean Ratio Allocated Alloc Ratio
Newtonsoft 10000 26.363 ms 1.00 10.55 MB 1.00
Microsoft 10000 15.020 ms 1.00 5.92 MB 1.00

Notably, comparing Newtonsoft to Microsoft in deserialization, there haven’t been substantial changes over the past year. While Microsoft appears to have made small optimizations in memory allocation, the overall trend indicates that Microsoft is much faster than Newtonsoft.

Deserialize Many Small Data Objects

Finally, we’ll benchmark the deserialization of many small objects from a List<string>.

[Benchmark]
public void NewtonsoftDeserializeIndividualData()
{
    foreach (var user in serializedTestUsersList)
    {
        _ = Newtonsoft.Json.JsonConvert.DeserializeObject<User>(user);
    }
}

[Benchmark]
public void MicrosoftDeserializeIndividualData()
{
    foreach (var user in serializedTestUsersList)
    {
        _ = System.Text.Json.JsonSerializer.Deserialize<User>(user);
    }
}

Results:

Individual Data Method Count Mean Ratio Allocated Alloc Ratio
Newtonsoft 10000 15.974 ms 1.00 35.5 MB 1.00
Microsoft 10000 8.472 ms 1.00 3.96 MB 1.00

Once again, Microsoft demonstrates nearly twice the speed and astonishingly requires over 30 MB less than Newtonsoft for deserialization. This echoes the findings of the .NET 7 benchmark, indicating a consistent performance advantage for Microsoft. Additionally, it seems that Microsoft has made further optimizations, using slightly less memory than last year.

Conclusion

In the realm of JSON serialization and deserialization within the .NET 8 landscape, our benchmarks present a compelling case. Despite claims of high performance from Newtonsoft.Json, the results unequivocally demonstrate that Microsoft’s System.Text.Json consistently outperforms its counterpart. Whether handling large or small datasets, System.Text.Json showcases superior speed and memory efficiency.

Key Takeaways:

  • Serialization and Deserialization Performance: System.Text.Json consistently excels in both serializing and deserializing tasks.
  • Memory Efficiency: The SDK-native package, System.Text.Json, not only outpaces Newtonsoft.Json in speed but also demonstrates remarkable efficiency in memory allocation.

These findings are specific to .NET 8, and it’s important to recognize that performance characteristics may vary with different versions. Building upon the insights gained from .NET 7, it’s reasonable to assert that System.Text.Json stands as the faster choice in all tested scenarios for .NET 7 and 8. While assumptions about future versions remain uncertain, the recent alignment of the creator of Newtonsoft.Json with Microsoft suggests a potential trajectory favoring System.Text.Json.

You can explore all the benchmark code used in this article on my GitHub repository: https://github.com/TrevorMcCubbin/DotnetBenchmarks

• • •

Original Article: .NET Performance #2: Newtonsoft vs. System.Text.Json by Tobias Streng

Similar
Mar 20
Author: Lorenzo Uriel
Nobody likes dealing with a slow query. Besides being stressfull to wait for, it can be a huge impact in your database.Some simpler approaches can help resolve this.I want to start a series of three articles explaining about Tuning and...
Mar 20
Author: Lorenzo Uriel
THE GREAT DAY HAS COME!I promise not to disappoint you, this is the last article in the series: SQL TuningIn all the articles I said that the recommendation was to read the execution plan, and guess what we are going...
Dec 1, 2023
Author: Rico Fritzsche
The flight monitor case study: Applying Vertical Slices in a real-world scenarioIn my last articles I talked about Vertical Slice Architecture and how to organize code in a non-technical way. I showed some simple examples of how to do this...
May 7
Author: Zeeshan Wazir
C# is a powerful programming language, widely used for software development across various domains. One crucial aspect of application development is dealing with PDFs, whether it's generating PDFs, extracting information from existing PDF documents, or manipulating PDF files.In this article,...
Send message
Email
Your name
*Message


© 1999–2024 WebDynamics
1980–... Sergey Drozdov
Area of interests: .NET Framework | .NET Core | C# | ASP.NET | Windows Forms | WPF | HTML5 | CSS3 | jQuery | AJAX | Angular | React | MS SQL Server | Transact-SQL | ADO.NET | Entity Framework | IIS | OOP | OOA | OOD | WCF | WPF | MSMQ | MVC | MVP | MVVM | Design Patterns | Enterprise Architecture | Scrum | Kanban