zoukankan      html  css  js  c++  java
  • .net core 在网络高并发下提高JSON的处理效率

    现有的webapi一般都基于JSON的格式来处理数据,由于JSON是一个文本类的序列化协议所以在性能上自然就相对低效一些。在.net中常用Newtonsoft.Json是最常用的组件,由于提供简便基于完整的jsonString方法使用起来非常方便;但也正是这原因导致Newtonsoft.Json在性能上一直被说慢,虽然Newtonsoft.Json提供Stream的方式来处理JSON不过想复用writerreader还是需要一些应用技巧。如果需要在网络通讯中应用JSON,那在这里介绍一下SpanJson这个组件,并通过一些测试来讲述如何使用它。

    SpanJson介绍

    SpanJson是一个性能相对不错的JSON组件,组件直接提供了byte[]和stream两种操作方式,而这两种方式非常适合在构建自有网络通讯上使用。通过这些基础的字节和流结构来处理可以相对降低一个大string的开销。不过这个组件的热度并不高,完善成度暂还不如Newtonsoft.Json,不过asp.net core 在FrameworkBenchmarks测试上已经引入。可以尝试一下使用,组件开源地址: https://github.com/Tornhoof/SpanJson

    性能测试

    组件提供的方法相对比较少,从设计上来说更多是针对通讯方面的支持。基于Stream的序列化可以直接挂载在NetStream上,这样可以节省数据复制带来的开销。不过反序列化不能直接在有混合数据的Stream上进行,这或多或少有些可惜。从issues的解答来看作者也不太愿意在混合数据流上进行调整。接下来针对bytesStream使用进行一个性能测试,而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);
            }
        }

    测试内容

    测试的方式主要针对一个简单的对象和一个对象列表,然后在不同线程下bytesStream 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:UsersAdministratorDesktopjson_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序列化处理。

    下载测试代码

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

  • 相关阅读:
    datanode报错Problem connecting to server
    使用命令查看hdfs的状态
    Access denied for user root. Superuser privilege is requ
    ElasticSearch默认的分页参数 size
    SparkStreaming Kafka 维护offset
    【容错篇】Spark Streaming的还原药水——Checkpoint
    251 Android 线性与相对布局简介
    250 Android Studio使用指南 总结
    249 如何解决项目导入产生的中文乱码问题
    248 gradle更新问题
  • 原文地址:https://www.cnblogs.com/smark/p/10689028.html
Copyright © 2011-2022 走看看