微軟終于追上了?

圖片來自 Glenn Carstens-Peters[1]Unsplash[2]
歡迎來到.NET 性能系列的另一章。這個系列的特點是對.NET 世界中許多不同的主題進行研究、基準和比較。正如標題所說的那樣,重點在于使用最新的.NET7 的性能。你將看到哪種方法是實現特定主題的最快方法,以及大量的技巧和竅門,你如何能以較低的努力最大化你的代碼性能。如果你對這些主題感興趣,請繼續關注
在這篇文章中,我們將比較兩個最突出的.NET 的 json 框架。:Newtonsofts Json.NET[3] 和 Microsofts System.Text.Json[4].
Newtonsoft.Json
是 NuGet 上下載量最大的軟件包,下載量超過23 億。System.Text.Json
稍稍落后,大約有6 億次下載。然而,我們需要考慮的是,System.Text.Json
自.NET Core 3.1 起就默認隨.NET SDK 交付。既然如此,Newtonsoft 似乎仍然是最受歡迎的 json 框架。讓我們來看看,它是否能保持它的名次,或者微軟是否在性能方面緩慢但肯定地領先。
測試方案
為了模擬現實生活中應用的真實場景,我們將測試兩個主要用例。
第一,單個大數據集的序列化和反序列化。
第二是許多小數據集的序列化和反序列化。
一個真實的場景也需要真實的數據。對于測試數據集,我決定使用 NuGet 包Bogus[5]。通過 Bogus,我能夠快速生成許多不同的用戶,包括個人姓名、電子郵件、ID 等。
[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);
}
對于基準,我們將使用每個軟件包的最新版本,目前是(2022 年 10 月):
Newtonsoft.Json — 13.0.1 and
System.Text.Json — 7.0.0-rc.2[6]
序列化測試
序列化大對象
為了測試一個大對象的序列化,我們簡單地使用List<User>
,我們在GlobalSetup()
方法中設置了它。我們的基準方法看起來像這樣:
[Benchmark(Baseline?=?true)]
public?void?NewtonsoftSerializeBigData()?=>_?=?Newtonsoft.Json.JsonConvert.SerializeObject(testUsers);[Benchmark]
public?void?MicrosoftSerializeBigData()?=>_?=?System.Text.Json.JsonSerializer.Serialize(testUsers);
這些方法都使用默認的ContractResolver
,它只被實例化一次,因此是兩個框架中性能最好的序列化選項。如果你使用自定義的JsonSerializerSettings
,注意不要多次實例化ContractResolver
,否則你會降低很多性能。
現在我們來看看結果:
Method | Count | Mean | Ratio | Allocated | Alloc Ratio |
---|---|---|---|---|---|
NewtonsoftSerializeBigData | 10000 | 7.609 ms | 1.00 | 8.09 MB | 1.00 |
MicrosoftSerializeBigData | 10000 | 3.712 ms | 0.49 | 3.42 MB | 0.42 |

盡管 Newtonsoft 在他們的第一個文檔網站[7]上說。
高性能:比.NET 的內置 JSON 序列化器快
我們可以清楚地看到,到目前為止,他們并不比內置的 JSON 序列化器快。至少在這個用例中是這樣。讓我們來看看,在其他使用情況下是否也是如此。
序列化許多小對象
這個用例在實際應用中比較常見,例如在 REST-Apis 中,每個網絡請求都必須處理 JSON 序列化數據,并且也要用 JSON 序列化數據進行響應。
為了實現這個用例,我們使用之前建立的List<User>
,并簡單地循環通過它,同時單獨序列化每個用戶。
[Benchmark(Baseline?=?true)]
public?void?NewtonsoftSerializeMuchData()
{foreach?(var?user?in?testUsers){_?=?Newtonsoft.Json.JsonConvert.SerializeObject(user);}
}[Benchmark]
public?void?MicrosoftSerializeMuchData()
{foreach?(var?user?in?testUsers){_?=?System.Text.Json.JsonSerializer.Serialize(user);}
}
在我的機器上,這個基準測試導致了以下結果:
Method | Count | Mean | Ratio | Allocated | Alloc Ratio |
---|---|---|---|---|---|
NewtonsoftSerializeMuchData | 10000 | 8.087 ms | 1.00 | 17.14 MB | 1.00 |
MicrosoftSerializeMuchData | 10000 | 3.944 ms | 0.49 | 3.64 MB | 0.21 |

我們可以看到對于許多小對象來說,性能又快了近 100%。不僅 System.Text.Json 的性能比 Newtonsoft 快了一倍,而且堆分配的內存甚至少了 5 倍! 正如我在以前的文章中提到的,節省堆內存甚至比速度更重要,你在這里看到了。堆內存最終將不得不被垃圾回收,這將阻塞你的整個應用程序的執行。
反序列化測試
在現實世界的應用中,你不僅要序列化,還要從 JSON 序列化的字符串中反序列化對象。在下面的基準中,我們將再次使用 Bogus,創建一組用戶,但這次我們要把它們序列化為一個大的字符串,用于大數據對象,并把許多小數據對象序列化為List<string>
。
private?string?serializedTestUsers;private?List<string>?serializedTestUsersList?=?new();[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())));var?testUsers?=?faker.Generate(Count);serializedTestUsers?=?JsonSerializer.Serialize(testUsers);foreach?(var?user?in?testUsers.Select(u?=>?JsonSerializer.Serialize(u))){serializedTestUsersList.Add(user);}
}
反序列化大對象
第一個反序列化基準將一個大的 JSON 字符串反序列化為相應的.NET 對象。在這種情況下,它又是List<User>
,我們在前面的例子中也使用了它。
[Benchmark(Baseline?=?true)]
public?void?NewtonsoftDeserializeBigData()?=>_?=?Newtonsoft.Json.JsonConvert.DeserializeObject<List<User>>(serializedTestUsers);[Benchmark]
public?void?MicrosoftDeserializeBigData()?=>_?=?System.Text.Json.JsonSerializer.Deserialize<List<User>>(serializedTestUsers);
在我的機器上運行這些基準測試,得出以下結果:
Method | Count | Mean | Ratio | Allocated | Alloc Ratio |
---|---|---|---|---|---|
NewtonsoftDeserializeBigData | 10000 | 21.20 ms | 1.00 | 10.55 MB | 1.00 |
MicrosoftDeserializeBigData | 10000 | 12.12 ms | 0.57 | 6.17 MB | 0.59 |

就性能而言,微軟仍然遠遠領先于 Newtonsoft。然而,我們可以看到,Newtonsoft 并沒有慢一半,而是慢了 40%左右,這在與序列化基準的直接比較中是一個進步。
反序列化許多小對象
本章的最后一個基準是許多小對象的反序列化。在這里,我們使用我們在上面的GlobalSetup()
方法中初始化的List<string>
,在一個循環中反序列化數據對象:
[Benchmark(Baseline?=?true)]
public?void?NewtonsoftDeserializeMuchData()
{foreach?(var?user?in?serializedTestUsersList){_?=?Newtonsoft.Json.JsonConvert.DeserializeObject<User>(user);}
}[Benchmark]
public?void?MicrosoftDeserializeMuchData()
{foreach?(var?user?in?serializedTestUsersList){_?=?System.Text.Json.JsonSerializer.Deserialize<User>(user);}
}
其結果甚至比相關的序列化基準更令人吃驚:
Method | Count | Mean | Ratio | Allocated | Alloc Ratio |
---|---|---|---|---|---|
NewtonsoftDeserializeMuchData | 10000 | 15.577 ms | 1.00 | 35.54 MB | 1.00 |
MicrosoftDeserializeMuchData | 10000 | 7.916 ms | 0.51 | 4.8 MB | 0.14 |

在 Microsofts 框架下,速度又快了一倍,內存效率是驚人的7倍,比 Newtonsoft 還要好!
總結
盡管 Newtonsoft 在他們的文檔[8]上說:
高性能:比.NET 的內置 JSON 序列化器更快
很明顯,至少從.NET 7 開始,Microsofts 的System.Text.Json
在所有測試的用例中至少快了一倍,命名為。
序列化一個大數據集
序列化許多小數據集
對一個大數據集進行反序列化
對許多小數據集進行反序列化
所有這些都是在每個框架的默認序列化器設置下進行的。
不僅速度快了 100%,而且在某些情況下,分配的內存甚至比 Newtonsoft 的效率高 5 倍以上。
我甚至認為,可以推斷出結果,目前使用System.Text.Json
比Newtonsoft.Json
更快。
請記住,這些結果只對最新的.NET 7 有效。如果你使用的是其他版本的.NET,情況可能正好相反,Newtonsoft 可能會更快。
我希望,我的文章可以幫助你對序列化器做出選擇選擇,并讓你對性能和基準測試的世界有一個有趣的切入點。
如果你喜歡這個系列的文章,請一定要關注我,因為還有很多有趣的話題等著你。
謝謝你的閱讀!
版權
原文版權:Tobias Streng
翻譯版權:InCerry
原文鏈接:https://medium.com/@tobias.streng/net-performance-series-2-newtonsoft-vs-system-text-json-2bf43e037db0
參考資料
[1]
Glenn Carstens-Peters: https://unsplash.com/@glenncarstenspeters?utm_source=medium&utm_medium=referral
[2]Unsplash: https://unsplash.com/?utm_source=medium&utm_medium=referral
[3]Newtonsofts Json.NET: https://www.newtonsoft.com/json
[4]Microsofts System.Text.Json: https://www.nuget.org/packages/System.Text.Json
[5]Bogus: https://github.com/bchavez/Bogus
[6]7.0.0-rc.2: https://www.nuget.org/packages/System.Text.Json/7.0.0-rc.2.22472.3
[7]第一個文檔網站: https://www.newtonsoft.com/json/help/html/Introduction.htm
[8]文檔: https://www.newtonsoft.com/json/help/html/Introduction.htm