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:
237

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
Oct 24, 2022
Author: Henrique Siebert Domareski
Singleton and Static classes can only have one instance available in memory, and both classes can be used to maintain the global state of an application, however, there are many differences between them. In this article, I explain what their...
May 14
Author: Brian Gorman
The Schema.org vocabulary is the ultimate collab.Thanks to a mutual handshake between Google, Microsoft, Yahoo, and Yandex, we have a library of fields we can use to highlight and more aptly define the information on web pages. By utilizing structured...
May 2
Author: Ankit Sahu
IntroductionCreating a CRUD (Create, Read, Update, Delete) API in .NET 8 with an In-memory collection is a common scenario in web development. In this article, we’ll walk through building a complete .NET 8 Web API with a real-world use case.PrerequisitesVisual...
Mar 30, 2021
Author: Nastassia Ovchinnikova
Let’s start the battle TypeScript vs JavaScript with an introduction of both technologies. JavaScript is a scripting language, that was developed by EMCA’s Technical Committee and Brendan Eich. It works perfectly in web-browsers without the help of any web-server or...
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