.net core 在網絡高併發下提升JSON的處理效率

現有的webapi通常都基於JSON的格式來處理數據,因爲JSON是一個文本類的序列化協議因此在性能上天然就相對低效一些。在.net中經常使用Newtonsoft.Json是最經常使用的組件,因爲提供簡便基於完整的jsonString方法使用起來很是方便;但也正是這緣由致使Newtonsoft.Json在性能上一直被說慢,雖然Newtonsoft.Json提供Stream的方式來處理JSON不過想複用writerreader仍是須要一些應用技巧。若是須要在網絡通信中應用JSON,那在這裏介紹一下SpanJson這個組件,並經過一些測試來說述如何使用它。git

SpanJson介紹

SpanJson是一個性能相對不錯的JSON組件,組件直接提供了byte[]和stream兩種操做方式,而這兩種方式很是適合在構建自有網絡通信上使用。經過這些基礎的字節和流結構來處理能夠相對下降一個大string的開銷。不過這個組件的熱度並不高,完善成度暫還不如Newtonsoft.Json,不過asp.net core 在FrameworkBenchmarks測試上已經引入。能夠嘗試一下使用,組件開源地址: https://github.com/Tornhoof/SpanJsongithub

性能測試

組件提供的方法相對比較少,從設計上來講更可能是針對通信方面的支持。基於Stream的序列化能夠直接掛載在NetStream上,這樣能夠節省數據複製帶來的開銷。不過反序列化不能直接在有混合數據的Stream上進行,這或多或少有些惋惜。從issues的解答來看做者也不太願意在混合數據流上進行調整。接下來針對bytesStream使用進行一個性能測試,而Stream則採用一個可複用池的設計web

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);
        }
    }

測試內容

測試的方式主要針對一個簡單的對象和一個對象列表,而後在不一樣線程下bytesStream pool這兩種方式的性能差異;壓測的線程數據分別是1,2,4,8,16,24,32,每次測試執行的總數是100萬次,而後統計出執行須要的時間和併發量。 測試代碼:json

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

總結

從測試結果來看,若是序列化的對象比小,那能夠直接基於bytes的方式。雖然會產生新的bytes對象,不過因爲對象比較小,引發的分配和回收並無對象池操做上的損耗高。不過若是對象相對複雜些的狀況下,那對象池的做用就能發揮出來,併發越大其做用越明顯!,當併發線程數達到8的時候,效率已經明顯拋開!因爲業務上的數據信息都相對比較複雜些,因此在處理上仍是建議經過對象池的方式來完成json序列化處理。api

下載測試代碼

http://ikende.com/Files/JsonSample.zipruby

相關文章
相關標籤/搜索