现有的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 池的设计

  1. public class MemoryStreamPool
  2. {
  3.  
  4. private static System.Collections.Concurrent.ConcurrentStack<JsonMemoryStream> mPool = new System.Collections.Concurrent.ConcurrentStack<JsonMemoryStream>();
  5.  
  6. public static Stream Pop()
  7. {
  8. if (!mPool.TryPop(out JsonMemoryStream result))
  9. {
  10. result = new JsonMemoryStream( * );
  11. }
  12. return result;
  13. }
  14.  
  15. public class JsonMemoryStream : MemoryStream
  16. {
  17. public JsonMemoryStream(int size) : base(size) { }
  18.  
  19. protected override void Dispose(bool disposing)
  20. {
  21. MemoryStreamPool.Push(this);
  22. }
  23.  
  24. }
  25.  
  26. private static void Push(JsonMemoryStream stream)
  27. {
  28. stream.Position = ;
  29. stream.SetLength();
  30. mPool.Push(stream);
  31. }
  32. }

测试内容

测试的方式主要针对一个简单的对象和一个对象列表,然后在不同线程下bytesStream pool这两种方式的性能差别;压测的线程数据分别是1,2,4,8,16,24,32,每次测试执行的总数是100万次,然后统计出执行需要的时间和并发量。 测试代码:

  1. public class Bytes_JSON : BeetleX.Benchmark.BenchmarkBase
  2. {
  3. protected override void OnTest()
  4. {
  5. while (Increment())
  6. {
  7. var data = SpanJson.JsonSerializer.NonGeneric.Utf8.Serialize(DataHelper.Defalut.Employees[]);
  8. var employees = SpanJson.JsonSerializer.Generic.Utf8.Deserialize<Employee>(data);
  9. }
  10. }
  11. }
  12.  
  13. public class StreamPool_JSON : BeetleX.Benchmark.BenchmarkBase
  14. {
  15. protected override void OnTest()
  16. {
  17. RunTest();
  18. }
  19.  
  20. private async void RunTest()
  21. {
  22. while (Increment())
  23. {
  24. using (Stream stream = MemoryStreamPool.Pop())
  25. {
  26. await SpanJson.JsonSerializer.NonGeneric.Utf8.SerializeAsync(DataHelper.Defalut.Employees[], stream);
  27. stream.Position = ;
  28. var employees = await SpanJson.JsonSerializer.Generic.Utf8.DeserializeAsync<Employee>(stream);
  29. }
  30. }
  31. }
  32. }
  33.  
  34. public class Bytes_JSON_List : BeetleX.Benchmark.BenchmarkBase
  35. {
  36. protected override void OnTest()
  37. {
  38. while (Increment())
  39. {
  40. var data = SpanJson.JsonSerializer.NonGeneric.Utf8.Serialize(DataHelper.Defalut.Employees);
  41. var employees = SpanJson.JsonSerializer.Generic.Utf8.Deserialize<List<Employee>>(data);
  42. }
  43. }
  44. }
  45.  
  46. public class StreamPool_JSON_List : BeetleX.Benchmark.BenchmarkBase
  47. {
  48. protected override void OnTest()
  49. {
  50. RunTest();
  51. }
  52.  
  53. private async void RunTest()
  54. {
  55. while (Increment())
  56. {
  57. using (Stream stream = MemoryStreamPool.Pop())
  58. {
  59. await SpanJson.JsonSerializer.NonGeneric.Utf8.SerializeAsync(DataHelper.Defalut.Employees, stream);
  60. stream.Position = ;
  61. var employees = await SpanJson.JsonSerializer.Generic.Utf8.DeserializeAsync<List<Employee>>(stream);
  62. }
  63. }
  64. }
  65. }

测试结果


  1. C:\Users\Administrator\Desktop\json_test>dotnet JsonSample.dll
  2. BeetleX.Benchmark [0.5.4.0] Copyright ? ikende.com 2019
  3. EMail:henryfan@msn.com
  4. Github:https://github.com/ikende
  5. -------------------------------------------------------------------------------
  6. |Name | Round| Threads| Count| Use time(s)| Sec|
  7. -------------------------------------------------------------------------------
  8. |Bytes_JSON | 1| 1| 1000000| 5.57|179580|
  9. -------------------------------------------------------------------------------
  10. |StreamPool_JSON | 1| 1| 1000000| 5.44|183898|
  11. -------------------------------------------------------------------------------
  12. |Bytes_JSON_List | 1| 1| 1000000| 43.01| 23248|
  13. -------------------------------------------------------------------------------
  14. |StreamPool_JSON_List | 1| 1| 1000000| 42.75| 23391|
  15. -------------------------------------------------------------------------------
  16. |Bytes_JSON | 1| 2| 1000000| 2.81|355990|
  17. -------------------------------------------------------------------------------
  18. |StreamPool_JSON | 1| 2| 1000000| 2.95|338969|
  19. -------------------------------------------------------------------------------
  20. |Bytes_JSON_List | 1| 2| 1000000| 23.16| 43180|
  21. -------------------------------------------------------------------------------
  22. |StreamPool_JSON_List | 1| 2| 1000000| 22.4| 44650|
  23. -------------------------------------------------------------------------------
  24. |Bytes_JSON | 1| 4| 1000000| 1.51|661246|
  25. -------------------------------------------------------------------------------
  26. |StreamPool_JSON | 1| 4| 1000000| 1.57|636130|
  27. -------------------------------------------------------------------------------
  28. |Bytes_JSON_List | 1| 4| 1000000| 13.35| 74915|
  29. -------------------------------------------------------------------------------
  30. |StreamPool_JSON_List | 1| 4| 1000000| 11.97| 83508|
  31. -------------------------------------------------------------------------------
  32. |Bytes_JSON | 1| 8| 1000000| .83|1199453|
  33. --------------------------------------------------------------------------------
  34. |StreamPool_JSON | 1| 8| 1000000| .88|1142495|
  35. --------------------------------------------------------------------------------
  36. |Bytes_JSON_List | 1| 8| 1000000| 9.24|108228|
  37. -------------------------------------------------------------------------------
  38. |StreamPool_JSON_List | 1| 8| 1000000| 6.75|148132|
  39. -------------------------------------------------------------------------------
  40. |Bytes_JSON | 1| 16| 1000000| .56|1795910|
  41. --------------------------------------------------------------------------------
  42. |StreamPool_JSON | 1| 16| 1000000| .74|1344851|
  43. --------------------------------------------------------------------------------
  44. |Bytes_JSON_List | 1| 16| 1000000| 7.67|130424|
  45. -------------------------------------------------------------------------------
  46. |StreamPool_JSON_List | 1| 16| 1000000| 4.61|216860|
  47. -------------------------------------------------------------------------------
  48. |Bytes_JSON | 1| 24| 1000000| .54|1849769|
  49. --------------------------------------------------------------------------------
  50. |StreamPool_JSON | 1| 24| 1000000| .73|1361382|
  51. --------------------------------------------------------------------------------
  52. |Bytes_JSON_List | 1| 24| 1000000| 7.61|131373|
  53. -------------------------------------------------------------------------------
  54. |StreamPool_JSON_List | 1| 24| 1000000| 4.7|212779|
  55. -------------------------------------------------------------------------------
  56. |Bytes_JSON | 1| 32| 1000000| .55|1825484|
  57. --------------------------------------------------------------------------------
  58. |StreamPool_JSON | 1| 32| 1000000| .75|1339050|
  59. --------------------------------------------------------------------------------
  60. |Bytes_JSON_List | 1| 32| 1000000| 8.01|124885|
  61. -------------------------------------------------------------------------------
  62. |StreamPool_JSON_List | 1| 32| 1000000| 5.21|192038|
  63. -------------------------------------------------------------------------------
  64. Test completed!

总结

从测试结果来看,如果序列化的对象比小,那可以直接基于bytes的方式。虽然会产生新的bytes对象,不过由于对象比较小,引起的分配和回收并没有对象池操作上的损耗高。不过如果对象相对复杂些的情况下,那对象池的作用就能发挥出来,并发越大其作用越明显!,当并发线程数达到8的时候,效率已经明显抛开!由于业务上的数据信息都相对比较复杂些,所以在处理上还是建议通过对象池的方式来完成json序列化处理。

下载测试代码

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

.net core 在网络高并发下提高JSON的处理效率的更多相关文章

  1. Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解

    Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解 说明:Java生鲜电商平台-生鲜电商高并发下的接口幂等性实现与代码讲解,实际系统中有很多操作,是不管做多少次,都应该产生一样的效果或返 ...

  2. 异构去堆叠 | 一种完美提升网络高可用SLA的方案

    行业内接入网络去堆叠已经逐步成为主流方向,在大型互联网公司也已经批量部署.但由于京东集团不同的业务需求及历史原因,没有条件完全复制目前主流的ARP转主机路由方式的去堆叠方案,这促使我们设计一种尽可能满 ...

  3. 高并发下的Java数据结构(List、Set、Map、Queue)

    由于并行程序与串行程序的不同特点,适用于串行程序的一些数据结构可能无法直接在并发环境下正常工作,这是因为这些数据结构不是线程安全的.本节将着重介绍一些可以用于多线程环境的数据结构,如并发List.并发 ...

  4. 分布式高并发下Actor模型

    分布式高并发下Actor模型 写在开始 一般来说有两种策略用来在并发线程中进行通信:共享数据和消息传递.使用共享数据方式的并发编程面临的最大的一个问题就是数据条件竞争.处理各种锁的问题是让人十分头痛的 ...

  5. JDK1.7 高并发下的HashMap

    HashMap的容量是有限的.当经过多次元素插入,使得HashMap达到一定饱和度时,Key映射位置发生冲突的几率会逐渐提高. 这时候,HashMap需要扩展它的长度,也就是进行Resize. 影响发 ...

  6. [Redis] - 高并发下Redis缓存穿透解决

    高并发情况下,可能都要访问数据库,因为同时访问的方法,这时需要加入同步锁,当其中一个缓存获取后,其它的就要通过缓存获取数据. 方法一: 在方法上加上同步锁 synchronized //加同步锁,解决 ...

  7. 对HashMap的理解(二):高并发下的HashMap

    在分析hashmap高并发场景之前,我们要先搞清楚ReHash这个概念.ReHash是HashMap在扩容时的一个步骤.HashMap的容量是有限的.当经过多次元素插入,使得HashMap达到一定饱和 ...

  8. springboot~高并发下耗时操作的实现

    高并发下的耗时操作 高并发下,就是请求在一个时间点比较多时,很多写的请求打过来时,你的服务器承受很大的压力,当你的一个请求处理时间长时,这些请求将会把你的服务器线程耗尽,即你的主线程池里的线程将不会再 ...

  9. 用ASP.NET Core构建可检测的高可用服务--学习笔记

    摘要 随着现代化微服务架构的发展,系统故障的定位与快速恢复面临着诸多挑战,构建可检测的服务,帮助线上保障团队时刻掌控应用的运行状况越来越重要.本次分享会讲解如何让 ASP .NET Core 应用与现 ...

随机推荐

  1. JS windows对象的top属性

    原博文:http://www.jb51.net/article/44078.htm   本文为大家介绍下JS window对象的top.parent.opener含义,不了解的朋友可以参考下,希望对大 ...

  2. Linux基础命令归纳大全

    Linux发行版本:基于linux内核提供桌面环境及办公套件的操作系统 (Linux内核只有一个)   1. 启动终端的快捷键: ctr + alt + t 2. 终端字体放大: ctr+shift+ ...

  3. Java核心卷笔记(一)

    第三章Java基程序设计结构 1.注释 三种注释方式: // 注释单行 /* 内容 */ 注释单行 /** * 内容 */ 2. java 数据类型 Java数据类型可分为两种:基本数据类型和引用数据 ...

  4. SSH项目的pom.xml文件

    <!-- 属性 --> <properties> <spring.version>4.2.4.RELEASE</spring.version> < ...

  5. java 引用数据类型(类)

    我们可以把类的类型为两种: 第一种,Java为我们提供好的类,如Scanner类,Random类等,这些已存在的类中包含了很多的方法与属性,可供我们使用. 第二种,我们自己创建的类,按照类的定义标准, ...

  6. js相关

    记录工作中用到的js实用方法: 1. 判断包含:indexOf "https".indexOf("http") 包含结果为0,不包含结果为-1: 通常用(&qu ...

  7. arcEngine开发之查询的相关接口

    属性查询 IQueryDef 首先这个接口不能直接创建,可以由 IFeatureWorkspace 接口的CreateQueryDef创建. 这个接口有两个属性必须设置(帮助文档是这样说明的,但是实际 ...

  8. Spring Boot实战笔记(五)-- Spring高级话题(Spring Aware)

    一.Spring Aware Spring 依赖注入的最大亮点就是你所有的 Bean 对 Spring容器的存在是没有意识的.即你可以将你的容器替换成其他的容器,如Google Guice,这时 Be ...

  9. Mac下设置JAVA_HOME和MAVEN_HOME

    1.找到java安装路径 /usr/libexec/java_home 2.设置JAVA_HOME $ vim ~/.bash_profile ~/.bash_profile:每个用户都可使用该文件输 ...

  10. 【转】深入理解margin

    由浅入深漫谈margin属性 2007-3-18 上午 - HTML/CSS/XML/XSL - CSS - margin margin 在中文中我们翻译成外边距或者外补白(本文中引用外边距).他是元 ...