.net core如何在網(wǎng)絡(luò)高并發(fā)下提高JSON的處理效率詳解
前言
現(xiàn)有的webapi一般都基于JSON的格式來處理數(shù)據(jù),由于JSON是一個(gè)文本類的序列化協(xié)議所以在性能上自然就相對(duì)低效一些。在.net中常用Newtonsoft.Json是最常用的組件,由于提供簡(jiǎn)便基于完整的json的String方法使用起來非常方便;但也正是這原因?qū)е翹ewtonsoft.Json在性能上一直被說慢,雖然Newtonsoft.Json提供Stream的方式來處理JSON不過想復(fù)用writer和reader還是需要一些應(yīng)用技巧。如果需要在網(wǎng)絡(luò)通訊中應(yīng)用JSON,那在這里介紹一下SpanJson這個(gè)組件,并通過一些測(cè)試來講述如何使用它。
SpanJson介紹
SpanJson是一個(gè)性能相對(duì)不錯(cuò)的JSON組件,組件直接提供了byte[]和stream兩種操作方式,而這兩種方式非常適合在構(gòu)建自有網(wǎng)絡(luò)通訊上使用。通過這些基礎(chǔ)的字節(jié)和流結(jié)構(gòu)來處理可以相對(duì)降低一個(gè)大string的開銷。不過這個(gè)組件的熱度并不高,完善成度暫還不如Newtonsoft.Json,不過asp.net core 在FrameworkBenchmarks測(cè)試上已經(jīng)引入??梢試L試一下使用,組件開源地址: https://github.com/Tornhoof/SpanJson (本地下載)
性能測(cè)試
組件提供的方法相對(duì)比較少,從設(shè)計(jì)上來說更多是針對(duì)通訊方面的支持?;赟tream的序列化可以直接掛載在NetStream上,這樣可以節(jié)省數(shù)據(jù)復(fù)制帶來的開銷。不過反序列化不能直接在有混合數(shù)據(jù)的Stream上進(jìn)行,這或多或少有些可惜。從issues的解答來看作者也不太愿意在混合數(shù)據(jù)流上進(jìn)行調(diào)整。接下來針對(duì)bytes和Stream使用進(jìn)行一個(gè)性能測(cè)試,而Stream則采用一個(gè)可復(fù)用池的設(shè)計(jì)
MemoryStream 池的設(shè)計(jì)
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);
}
}
測(cè)試內(nèi)容
測(cè)試的方式主要針對(duì)一個(gè)簡(jiǎn)單的對(duì)象和一個(gè)對(duì)象列表,然后在不同線程下bytes和Stream pool這兩種方式的性能差別;壓測(cè)的線程數(shù)據(jù)分別是1,2,4,8,16,24,32,每次測(cè)試執(zhí)行的總數(shù)是100萬次,然后統(tǒng)計(jì)出執(zhí)行需要的時(shí)間和并發(fā)量。 測(cè)試代碼:
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è)試結(jié)果
C:\Users\Administrator\Desktop\json_test>dotnet JsonSample.dll
BeetleX.Benchmark [0.5.4.0] Copyright ? ikende.com 2019
EMail:henryfan@msn.com
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!
總結(jié)
從測(cè)試結(jié)果來看,如果序列化的對(duì)象比小,那可以直接基于bytes的方式。雖然會(huì)產(chǎn)生新的bytes對(duì)象,不過由于對(duì)象比較小,引起的分配和回收并沒有對(duì)象池操作上的損耗高。不過如果對(duì)象相對(duì)復(fù)雜些的情況下,那對(duì)象池的作用就能發(fā)揮出來,并發(fā)越大其作用越明顯!,當(dāng)并發(fā)線程數(shù)達(dá)到8的時(shí)候,效率已經(jīng)明顯拋開!由于業(yè)務(wù)上的數(shù)據(jù)信息都相對(duì)比較復(fù)雜些,所以在處理上還是建議通過對(duì)象池的方式來完成json序列化處理。
下載測(cè)試代碼:http://xiazai.jb51.net/201904/yuanma/JsonSample(jb51).rar
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
asp.net下使用jQuery.AutoComplete完成仿淘寶商品搜索自動(dòng)完成功能(改進(jìn)了鍵盤上下選擇體驗(yàn))
其實(shí)這個(gè)已經(jīng)是個(gè)比較常見的功能了,網(wǎng)上也有很多人做過這個(gè)了,但是很多都是僅僅做了一些基本的網(wǎng)頁上自動(dòng)完成功能,沒有與具體的數(shù)據(jù)庫進(jìn)行聯(lián)動(dòng),我今天所介紹這個(gè)自動(dòng)完成的就是我修改的jQuery.AutoComplete+數(shù)據(jù)庫的一個(gè)解決方案。2010-05-05
ASP.NET(C#) 讀取EXCEL另加解決日期問題的方法分享
這篇文章介紹了ASP.NET(C#) 讀取EXCEL另加解決日期問題的方法,有需要的朋友可以參考一下2013-11-11
Visual Studio IDE編寫程序時(shí)不顯示窗口或窗口一閃而逝的解決方法
這篇文章主要為大家詳細(xì)介紹了Visual Studio IDE編寫程序時(shí)不顯示窗口或窗口一閃而逝的解決方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-09-09
.NET Core讀取配置文件方式詳細(xì)總結(jié)
這篇文章主要為大家詳細(xì)總結(jié)了.NET Core讀取配置文件方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08
.NET?Core控制臺(tái)應(yīng)用ConsoleApp讀取appsettings.json配置文件
這篇文章介紹了.NET?Core控制臺(tái)應(yīng)用ConsoleApp讀取appsettings.json配置文件的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07

