這篇文章主要給大家介紹了關於.net core如何在網絡高併發下提高JSON的處理效率的相關資料,文中通過示例代碼介紹的非常詳細,對大家學習或者使用.net core具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧
前言
現有的webapi一般都基於JSON的格式來處理數據,由於JSON是一個文本類的序列化協議所以在性能上自然就相對低效一些。在.net中常用Newtonsoft.Json是最常用的組件,由於提供簡便基於完整的json的String方法使用起來非常方便;但也正是這原因導致Newtonsoft.Json在性能上一直被說慢,雖然Newtonsoft.Json提供Stream的方式來處理JSON不過想複用writer和reader還是需要一些應用技巧。如果需要在網絡通訊中應用JSON,那在這裏介紹一下SpanJson這個組件,並通過一些測試來講述如何使用它。
SpanJson介紹
SpanJson是一個性能相對不錯的JSON組件,組件直接提供了byte[]和stream兩種操作方式,而這兩種方式非常適合在構建自有網絡通訊上使用。通過這些基礎的字節和流結構來處理可以相對降低一個大string的開銷。不過這個組件的熱度並不高,完善成度暫還不如Newtonsoft.Json,不過asp.net core 在FrameworkBenchmarks測試上已經引入。可以嘗試一下使用,組件開源地址: https://github.com/Tornhoof/SpanJson (本地下載)
性能測試
組件提供的方法相對比較少,從設計上來說更多是針對通訊方面的支持。基於Stream的序列化可以直接掛載在NetStream上,這樣可以節省數據複製帶來的開銷。不過反序列化不能直接在有混合數據的Stream上進行,這或多或少有些可惜。從issues的解答來看作者也不太願意在混合數據流上進行調整。接下來針對bytes和Stream使用進行一個性能測試,而Stream則採用一個可複用池的設計
MemoryStream 池的設計
public class MemoryStreamPool { private static System.Collections.Concurrent.ConcurrentStack<JsonMemoryStream> mPool = new System.Collections.Concurrent.ConcurrentStack<JsonMemoryStream>(); public static Stream Pop() { if (!mPool.TryPop(out JsonMemoryStream result)) { result = new JsonMemoryStream(1024 * 32); } return result; } public class JsonMemoryStream : MemoryStream { public JsonMemoryStream(int size) : base(size) { } protected override void Dispose(bool disposing) { MemoryStreamPool.Push(this); } } private static void Push(JsonMemoryStream stream) { stream.Position = 0; stream.SetLength(0); mPool.Push(stream); } }
測試內容
測試的方式主要針對一個簡單的對象和一個對象列表,然後在不同線程下bytes和Stream pool這兩種方式的性能差別;壓測的線程數據分別是1,2,4,8,16,24,32,每次測試執行的總數是100萬次,然後統計出執行需要的時間和併發量。 測試代碼:
public class Bytes_JSON : BeetleX.Benchmark.BenchmarkBase { protected override void OnTest() { while (Increment()) { var data = SpanJson.JsonSerializer.NonGeneric.Utf8.Serialize(DataHelper.Defalut.Employees[0]); var employees = SpanJson.JsonSerializer.Generic.Utf8.Deserialize<Employee>(data); } } } public class StreamPool_JSON : BeetleX.Benchmark.BenchmarkBase { protected override void OnTest() { RunTest(); } private async void RunTest() { while (Increment()) { using (Stream stream = MemoryStreamPool.Pop()) { await SpanJson.JsonSerializer.NonGeneric.Utf8.SerializeAsync(DataHelper.Defalut.Employees[0], stream); stream.Position = 0; var employees = await SpanJson.JsonSerializer.Generic.Utf8.DeserializeAsync<Employee>(stream); } } } } public class Bytes_JSON_List : BeetleX.Benchmark.BenchmarkBase { protected override void OnTest() { while (Increment()) { var data = SpanJson.JsonSerializer.NonGeneric.Utf8.Serialize(DataHelper.Defalut.Employees); var employees = SpanJson.JsonSerializer.Generic.Utf8.Deserialize<List<Employee>>(data); } } } public class StreamPool_JSON_List : BeetleX.Benchmark.BenchmarkBase { protected override void OnTest() { RunTest(); } private async void RunTest() { while (Increment()) { using (Stream stream = MemoryStreamPool.Pop()) { await SpanJson.JsonSerializer.NonGeneric.Utf8.SerializeAsync(DataHelper.Defalut.Employees, stream); stream.Position = 0; var employees = await SpanJson.JsonSerializer.Generic.Utf8.DeserializeAsync<List<Employee>>(stream); } } } }
測試結果
C:\Users\Administrator\Desktop\json_test>dotnet JsonSample.dll
BeetleX.Benchmark [0.5.4.0] Copyright ? ikende.com 2019
EMail:[email protected]
Github:https://github.com/ikende
-------------------------------------------------------------------------------
|Name | Round| Threads| Count| Use time(s)| Sec|
-------------------------------------------------------------------------------
|Bytes_JSON | 1| 1| 1000000| 5.57|179580|
-------------------------------------------------------------------------------
|StreamPool_JSON | 1| 1| 1000000| 5.44|183898|
-------------------------------------------------------------------------------
|Bytes_JSON_List | 1| 1| 1000000| 43.01| 23248|
-------------------------------------------------------------------------------
|StreamPool_JSON_List | 1| 1| 1000000| 42.75| 23391|
-------------------------------------------------------------------------------
|Bytes_JSON | 1| 2| 1000000| 2.81|355990|
-------------------------------------------------------------------------------
|StreamPool_JSON | 1| 2| 1000000| 2.95|338969|
-------------------------------------------------------------------------------
|Bytes_JSON_List | 1| 2| 1000000| 23.16| 43180|
-------------------------------------------------------------------------------
|StreamPool_JSON_List | 1| 2| 1000000| 22.4| 44650|
-------------------------------------------------------------------------------
|Bytes_JSON | 1| 4| 1000000| 1.51|661246|
-------------------------------------------------------------------------------
|StreamPool_JSON | 1| 4| 1000000| 1.57|636130|
-------------------------------------------------------------------------------
|Bytes_JSON_List | 1| 4| 1000000| 13.35| 74915|
-------------------------------------------------------------------------------
|StreamPool_JSON_List | 1| 4| 1000000| 11.97| 83508|
-------------------------------------------------------------------------------
|Bytes_JSON | 1| 8| 1000000| .83|1199453|
--------------------------------------------------------------------------------
|StreamPool_JSON | 1| 8| 1000000| .88|1142495|
--------------------------------------------------------------------------------
|Bytes_JSON_List | 1| 8| 1000000| 9.24|108228|
-------------------------------------------------------------------------------
|StreamPool_JSON_List | 1| 8| 1000000| 6.75|148132|
-------------------------------------------------------------------------------
|Bytes_JSON | 1| 16| 1000000| .56|1795910|
--------------------------------------------------------------------------------
|StreamPool_JSON | 1| 16| 1000000| .74|1344851|
--------------------------------------------------------------------------------
|Bytes_JSON_List | 1| 16| 1000000| 7.67|130424|
-------------------------------------------------------------------------------
|StreamPool_JSON_List | 1| 16| 1000000| 4.61|216860|
-------------------------------------------------------------------------------
|Bytes_JSON | 1| 24| 1000000| .54|1849769|
--------------------------------------------------------------------------------
|StreamPool_JSON | 1| 24| 1000000| .73|1361382|
--------------------------------------------------------------------------------
|Bytes_JSON_List | 1| 24| 1000000| 7.61|131373|
-------------------------------------------------------------------------------
|StreamPool_JSON_List | 1| 24| 1000000| 4.7|212779|
-------------------------------------------------------------------------------
|Bytes_JSON | 1| 32| 1000000| .55|1825484|
--------------------------------------------------------------------------------
|StreamPool_JSON | 1| 32| 1000000| .75|1339050|
--------------------------------------------------------------------------------
|Bytes_JSON_List | 1| 32| 1000000| 8.01|124885|
-------------------------------------------------------------------------------
|StreamPool_JSON_List | 1| 32| 1000000| 5.21|192038|
-------------------------------------------------------------------------------
Test completed!
總結
從測試結果來看,如果序列化的對象比小,那可以直接基於bytes的方式。雖然會產生新的bytes對象,不過由於對象比較小,引起的分配和回收並沒有對象池操作上的損耗高。不過如果對象相對複雜些的情況下,那對象池的作用就能發揮出來,併發越大其作用越明顯!,當併發線程數達到8的時候,效率已經明顯拋開!由於業務上的數據信息都相對比較複雜些,所以在處理上還是建議通過對象池的方式來完成json序列化處理。
下載測試代碼:http://xiazai.jb51.net/201904/yuanma/JsonSample(jb51).rar
好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對神馬文庫的支持。