.net 各种序列化方式效率对比

在服务与服务之间传输的是二进制数据,而在此之前有多种方法将数据内容进行序列化来减小数据传递大小,现针对于目前主流的几种序列化方式做了简单数据统计对比。

先做下简单介绍↓↓↓

1、protobuf-net

protobuf-net is a contract based serializer for .NET code, that happens to write data in the "protocol buffers" serialization format engineered by Google. The API, however, is very different to Google‘s, and follows typical .NET patterns (it is broadly comparable, in usage, to XmlSerializer, DataContractSerializer, etc). It should work for most .NET languages that write standard types and can use attributes.

    GitHub地址:https://github.com/mgravell/protobuf-net

  

  2、Newtonsoft.Json(Json.Net)

  Json.NET is a personal open source project. Started in 2006, thousands of hours have been invested in refining and tuning Json.NET with the goal of making it not just the best JSON serializer for .NET but the best serializer for any computer language.

   官网:https://www.newtonsoft.com/json

  3、DataContractSerializer 

     Use the DataContractSerializer class to serialize and deserialize instances of a type into an XML stream or document. For example, you can create a type named Person with properties that contain essential data, such as a name and address. You can then create and manipulate an instance of the Person class and write all of its property values in an XML document for later retrieval, or in an XML stream for immediate transport. Most important, the DataContractSerializer is used to serialize and deserialize data sent in Windows Communication Foundation (WCF) messages. Apply the DataContractAttribute attribute to classes, and the DataMemberAttribute attribute to class members to specify properties and fields that are serialized.

MSDN:  https://msdn.microsoft.com/en-us/library/system.runtime.serialization.datacontractserializer(v=vs.110).aspx

  

   现对于这三种序列化方式从序列化后数据大小、序列化耗时、反序列化耗时进行统计对比。

   版本:protobuf-net-2.3.2.0、Newtonsoft.Json-6.0.4

  

    统计代码:

  1     class Program
  2     {
  3         static void Main(string[] args)
  4         {
  5             Console.WriteLine();
  6             Console.WriteLine("****************第一次测试****************");
  7             Console.WriteLine();
  8             TestMain(500);
  9             Console.WriteLine();
 10             Console.WriteLine("****************第二次测试****************");
 11             Console.WriteLine();
 12             TestMain(5000);
 13             Console.WriteLine();
 14             Console.WriteLine("****************第三次测试****************");
 15             Console.WriteLine();
 16             TestMain(50000);
 17             Console.Read();
 18         }
 19
 20         #region Private
 21
 22         private static void TestMain(int count)
 23         {
 24             var list = GetList(count);
 25
 26             var pbSerializeTime = 0.00;
 27             var pbDeSerializeTime = 0.00;
 28
 29             var jsonSerializeTime = 0.00;
 30             var jsonDeSerializeTime = 0.00;
 31
 32             var dataContractSerializeTime = 0.00;
 33             var dataContractDeSerializeTime = 0.00;
 34
 35             Console.WriteLine();
 36
 37             //protobuf-net
 38             Console.WriteLine("---------------protobuf-net--------------");
 39             Stopwatch watch = new Stopwatch();
 40             watch.Start();
 41             var pbResult = ProtobufSerialize(list);
 42             File.WriteAllText($@"D:\Code\WCF数据压缩传输\WcfTest{DateTime.Now.ToString("yyyyMMddHHmmss")}.txt", pbResult);
 43             watch.Stop();
 44
 45             pbSerializeTime = watch.ElapsedMilliseconds;
 46             Console.WriteLine();
 47             Console.WriteLine($"序列化后数据大小:{HumanReadableFilesize(pbResult.Length)}");
 48             Console.WriteLine();
 49             Console.WriteLine($"序列化耗时:{watch.ElapsedMilliseconds} 毫秒");
 50             Console.WriteLine();
 51
 52             watch = new Stopwatch();
 53             watch.Start();
 54             var pbValue = ProtobufDeSerialize<List<TransmissionModel>>(pbResult);
 55             watch.Stop();
 56             pbDeSerializeTime = watch.ElapsedMilliseconds;
 57             Console.WriteLine($"反序列化耗时:{watch.ElapsedMilliseconds} 毫秒");
 58             Console.WriteLine();
 59
 60             Console.WriteLine($"反序列化结果验证:{pbValue[0].Name}:{!string.IsNullOrWhiteSpace(pbValue[0].Name)}");
 61             Console.WriteLine();
 62
 63             //Newtonsoft.Json
 64             Console.WriteLine("---------------Newtonsoft.Json--------------");
 65             Console.WriteLine();
 66             watch = new Stopwatch();
 67             watch.Start();
 68             var jsonResult = Newtonsoft.Json.JsonConvert.SerializeObject(list);
 69             File.WriteAllText($@"D:\Code\WCF数据压缩传输\WcfTest{DateTime.Now.AddSeconds(1).ToString("yyyyMMddHHmmss")}.txt", jsonResult);
 70             watch.Stop();
 71             jsonSerializeTime = watch.ElapsedMilliseconds;
 72             Console.WriteLine($"序列化后数据大小:{HumanReadableFilesize(jsonResult.Length)}");
 73             Console.WriteLine();
 74             Console.WriteLine($"序列化耗时:{watch.ElapsedMilliseconds} 毫秒");
 75             Console.WriteLine();
 76
 77             watch = new Stopwatch();
 78             watch.Start();
 79             var jsonValue = Newtonsoft.Json.JsonConvert.DeserializeObject<List<TransmissionModel>>(jsonResult);
 80             watch.Stop();
 81             jsonDeSerializeTime = watch.ElapsedMilliseconds;
 82             Console.WriteLine($"反序列化耗时:{watch.ElapsedMilliseconds} 毫秒");
 83             Console.WriteLine();
 84
 85             Console.WriteLine($"反序列化结果验证:{jsonValue[0].Name}:{!string.IsNullOrWhiteSpace(jsonValue[0].Name)}");
 86             Console.WriteLine();
 87
 88             //DataContractSerializer
 89             Console.WriteLine("---------------DataContractSerializer--------------");
 90             Console.WriteLine();
 91
 92             watch = new Stopwatch();
 93             watch.Start();
 94             var dataContractFileName = $@"D:\Code\WCF数据压缩传输\WcfTest{DateTime.Now.AddSeconds(2).ToString("yyyyMMddHHmmss")}.txt";
 95             var dataContractSerializer = new DataContractSerializer(typeof(List<TransmissionModel>));
 96             var dataContractfi = new FileInfo(dataContractFileName);
 97             using (var stream = dataContractfi.Create())
 98             {
 99                 dataContractSerializer.WriteObject(stream, list);
100             }
101             watch.Stop();
102             dataContractSerializeTime = watch.ElapsedMilliseconds;
103             Console.WriteLine($"序列化后数据大小:{HumanReadableFilesize(dataContractfi.Length)}");
104             Console.WriteLine();
105             Console.WriteLine($"序列化耗时:{watch.ElapsedMilliseconds} 毫秒");
106             Console.WriteLine();
107
108             watch = new Stopwatch();
109             watch.Start();
110             var dataContractValue = new List<TransmissionModel>();
111             DataContractSerializer serializer = new DataContractSerializer(typeof(List<TransmissionModel>));
112             using (FileStream fs = new FileStream(dataContractFileName, FileMode.Open, FileAccess.Read))
113             {
114                 using (XmlReader reader = new XmlTextReader(dataContractFileName, fs))
115                 {
116                     dataContractValue = (List<TransmissionModel>)serializer.ReadObject(reader);
117                 }
118             }
119             watch.Stop();
120             dataContractDeSerializeTime = watch.ElapsedMilliseconds;
121             Console.WriteLine($"反序列化耗时:{watch.ElapsedMilliseconds} 毫秒");
122             Console.WriteLine();
123             Console.WriteLine($"反序列化结果验证:{dataContractValue[0].Name}:{!string.IsNullOrWhiteSpace(dataContractValue[0].Name)}");
124
125             //统计结果
126             Console.WriteLine();
127             Console.WriteLine($"=====================统计结果======================");
128             Console.WriteLine();
129             Console.WriteLine($"protobuf-net序列化后数据大小为Newtonsoft.Json的 {Math.Round(pbResult.Length / Convert.ToDouble(jsonResult.Length), 2) * 100}%,为DataContractSerializer的 {Math.Round(pbResult.Length / Convert.ToDouble(dataContractfi.Length), 2) * 100}%");
130             Console.WriteLine();
131             Console.WriteLine($"protobuf-net序列化耗时为Newtonsoft.Json的 {Math.Round(pbSerializeTime / jsonSerializeTime, 2) * 100}%,为DataContractSerializer的 {Math.Round(pbSerializeTime / dataContractSerializeTime, 2) * 100}%");
132             Console.WriteLine();
133             Console.WriteLine($"protobuf-net反序列耗时为Newtonsoft.Json的 {Math.Round(pbDeSerializeTime / jsonDeSerializeTime, 2) * 100}%,为DataContractSerializer的 {Math.Round(pbDeSerializeTime / dataContractDeSerializeTime, 2) * 100}%");
134             Console.WriteLine();
135         }
136
137         private static List<TransmissionModel> GetList(int count)
138         {
139             var list = new List<TransmissionModel>();
140             var model1 = new TransmissionModel() { ID = 1, Name = "我爱北京天安门", TempModel = new TempModel() { Age = 3, Name = "天安门上有毛爷爷" } };
141             var model2 = new TransmissionModel() { ID = 2, Name = "天安门上红旗飘", TempModel = new TempModel() { Age = 4, Name = "I Love 毛爷爷" } };
142             for (int i = 0; i < count; i++)
143             {
144                 list.Add(model1);
145                 list.Add(model2);
146             }
147             return list;
148         }
149
150         private static string ProtobufSerialize<T>(T obj)
151         {
152             using (var memory = new MemoryStream())
153             {
154                 Serializer.Serialize(memory, obj);
155                 return Encoding.UTF8.GetString(memory.ToArray());
156             }
157         }
158
159         /// <summary>
160         /// 反序列化
161         /// </summary>
162         /// <typeparam name="T"></typeparam>
163         /// <param name="content"></param>
164         /// <returns></returns>
165         private static T ProtobufDeSerialize<T>(string content)
166         {
167             using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(content)))
168             {
169                 T t = Serializer.Deserialize<T>(ms);
170                 return t;
171             }
172         }
173
174         /// <summary>
175         /// 转换方法
176         /// </summary>
177         /// <param name="size">字节值</param>
178         /// <returns></returns>
179         private static String HumanReadableFilesize(double size)
180         {
181             String[] units = new String[] { "B", "KB", "MB", "GB", "TB", "PB" };
182             double mod = 1024.0;
183             int i = 0;
184             while (size >= mod)
185             {
186                 size /= mod;
187                 i++;
188             }
189             return Math.Round(size) + units[i];
190         }
191         #endregion
192     }
193
194     [DataContract]
195     [ProtoContract]
196     class TransmissionModel
197     {
198         [DataMember]
199         [ProtoMember(1)]
200         public int ID { get; set; }
201
202         [DataMember]
203         [ProtoMember(2)]
204         public string Name { get; set; }
205
206         [DataMember]
207         [ProtoMember(3)]
208         public TempModel TempModel { get; set; }
209     }
210
211     [DataContract]
212     [ProtoContract]
213     class TempModel
214     {
215         [DataMember]
216         [ProtoMember(1)]
217         public int Age { get; set; }
218
219         [DataMember]
220         [ProtoMember(2)]
221         public string Name { get; set; }
222     }

  

    测试统计结果如下:

****************第一次测试****************

---------------protobuf-net--------------

序列化后数据大小:27KB

序列化耗时:171 毫秒

反序列化耗时:22 毫秒

反序列化结果验证:我爱北京天安门:True

---------------Newtonsoft.Json--------------

序列化后数据大小:65KB

序列化耗时:266 毫秒

反序列化耗时:99 毫秒

反序列化结果验证:我爱北京天安门:True

---------------DataContractSerializer--------------

序列化后数据大小:148KB

序列化耗时:49 毫秒

反序列化耗时:26 毫秒

反序列化结果验证:我爱北京天安门:True

=====================统计结果======================

protobuf-net序列化后数据大小为Newtonsoft.Json的 42%,为DataContractSerializer的 19%

protobuf-net序列化耗时为Newtonsoft.Json的 64%,为DataContractSerializer的 349%

protobuf-net反序列耗时为Newtonsoft.Json的 22%,为DataContractSerializer的 85%

****************第二次测试****************

---------------protobuf-net--------------

序列化后数据大小:273KB

序列化耗时:49 毫秒

反序列化耗时:26 毫秒

反序列化结果验证:我爱北京天安门:True

---------------Newtonsoft.Json--------------

序列化后数据大小:654KB

序列化耗时:63 毫秒

反序列化耗时:39 毫秒

反序列化结果验证:我爱北京天安门:True

---------------DataContractSerializer--------------

序列化后数据大小:1MB

序列化耗时:40 毫秒

反序列化耗时:89 毫秒

反序列化结果验证:我爱北京天安门:True

=====================统计结果======================

protobuf-net序列化后数据大小为Newtonsoft.Json的 42%,为DataContractSerializer的 19%

protobuf-net序列化耗时为Newtonsoft.Json的 78%,为DataContractSerializer的 123%

protobuf-net反序列耗时为Newtonsoft.Json的 67%,为DataContractSerializer的 29%

****************第三次测试****************

---------------protobuf-net--------------

序列化后数据大小:3MB

序列化耗时:366 毫秒

反序列化耗时:384 毫秒

反序列化结果验证:我爱北京天安门:True

---------------Newtonsoft.Json--------------

序列化后数据大小:6MB

序列化耗时:637 毫秒

反序列化耗时:569 毫秒

反序列化结果验证:我爱北京天安门:True

---------------DataContractSerializer--------------

序列化后数据大小:14MB

序列化耗时:384 毫秒

反序列化耗时:736 毫秒

反序列化结果验证:我爱北京天安门:True

=====================统计结果======================

protobuf-net序列化后数据大小为Newtonsoft.Json的 42%,为DataContractSerializer的 19%

protobuf-net序列化耗时为Newtonsoft.Json的 57%,为DataContractSerializer的 95%

protobuf-net反序列耗时为Newtonsoft.Json的 67%,为DataContractSerializer的 52%

  

    各序列化生成文件内容对比:

  protobuf-net:

  Newtonsoft.Json: DataContractSerializer:

   

     综合分析:

        1、数据内容格式及大小:DataContractSerializer(序列化为XML)> Newtonsoft.Json(序列化为Json文本) > protobuf-net(暂未知格式) ,protobuf-net 表现最优,protobuf-net序列化后数据大小为Newtonsoft.Json的 42%,为DataContractSerializer的 19%。
        2、序列化耗时最小方面:随着数据本身大小的变化各序列化耗时之间的排名有不同变化,表现较好的主要为 DataContractSerializer 和 protobuf-net ,三轮测试下来 Newtonsoft.Json 明显比其它两种序列化方式耗时长(详细查看上方测试统计数据)。
        3、反序列耗时最小方面:随着数据本身大小的变化排名也有不同变化,表现最好的为protobuf-net(详细查看上方测试统计数据)。

     客观结论:

      通过对比序列化后数据大小、序列化耗时、反序列化耗时、数据格式得出客观结论:protobuf-net 在整体效率上来说最优

关于 protobuf-net 的具体应用将会在下篇文章写出。

  以上仅为个人测试统计对比,欢迎提出建议指正。

   本文参考文章:http://www.cnblogs.com/onlytiancai/archive/2009/07/02/protobuf_net_test.html

↓↓↓欢迎关注我的公众号

时间: 09-21

.net 各种序列化方式效率对比的相关文章

Oracle常用导出导出命令及性能效率对比

说明 Oracle导入导出命令主要有EXPDP和IMPDP.EXP和IMP,区别如下:EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用.EXPDP和IMPDP是服务端的工具程序,他们只能在ORACLE服务端使用,不能在客户端使用.IMP只适用于EXP导出的文件,不适用于EXPDP导出文件:IMPDP只适用于EXPDP导出的文件,而不适用于EXP导出文件.expdp或impdp命令时,可暂不指出用户名/密码@实例名as 身份,然后根据提示再输入,如:expdp schem

Android中两种序列化方式的比较Serializable和Parcelable

Serializable和Parcelable接口可以完成对象的序列化过程,当我们需要通过Intent和Binder传输数据时就需要使用者两种序列化方式.还有,我们需要对象持久化到存储设备或者通过网络传输给其他客户端,这个使用也需要使用Serializale来完成对象的序列化.在Android应用开发中,这两种方式都很常见,但两者方式并不相同. 1.Serializable接口 Serializable接口是Java提供的一个序列化接口,它是一个空接口,为对象提供标准的序列化和反序列化操作.使用

几种Java序列化方式的实现

0.前言 本文主要对几种常见Java序列化方式进行实现.包括Java原生以流的方法进行的序列化.Json序列化.FastJson序列化.Protobuff序列化. 1.Java原生序列化 Java原生序列化方法即通过Java原生流(InputStream和OutputStream之间的转化)的方式进行转化.需要注意的是JavaBean实体类必须实现Serializable接口,否则无法序列化.Java原生序列化代码示例如下所示: package serialize; import java.io

java创建线程的三种方式及其对比

Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实例,即创建了线程对象. (3)调用线程对象的start()方法来启动该线程. package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重写run方法,run方法的方

CMap与hash_map效率对比

CMap与hash_map底层均采用hash stable实现,CMap是MFC提供的模板类.hash_map虽然目前并未纳入C++标准模板类库,但几乎每个版本的STL都提供了相应的实现.CMap与hash_map的存储于查询效率比较如下: 利用rand函数随机生成99999个整数构成查询数据集,紧接着申请9999个整数作为查询.测试两个模板类的插入与查询总时间,测试结果显示:当查询都不存在时CMap时间大约16ms,hash_map为0ms:当大部分查询存在时CMap时间为624,而hash_

Snapman系统中TCC执行效率和C#执行效率对比

Snapman集合了TCC编译器可以直接编译执行C语言脚本,其脚本执行效率和C#编译程序进行效率对比,包括下面3方面: 1.函数执行效率 2.数字转换成字符串 3.字符串的叠加 这是C#代码: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Tex

几种常见SQL分页方式效率比较-转

原文地址:几种常见SQL分页方式效率比较 分页很重要,面试会遇到.不妨再回顾总结一下. 1.创建测试环境,(插入100万条数据大概耗时5分钟). create database DBTestuse DBTest --创建测试表create table pagetest(id int identity(1,1) not null,col01 int null,col02 nvarchar(50) null,col03 datetime null) --1万记录集declare @i intset

java StringBuffer,StringBuilder,String自身连接效率对比

当我们仅仅需要a+b 的时候,两个字符串链接任何方法的效率基本一样,都在0.0001毫秒内就可以完成.不过如果需要1万次,10000万次,就会发现string自身的join速度显著下降 package com.java.lang; public class StringTest { int MAX = 10000; //1万次累加 public String Buffer(){ StringBuffer sb = new StringBuffer(); for(int i = 0; i < MA

java int转String所有方式的效率对比与深入解析

在java中,大家肯定都会遇到int类型转String类型的情形,知其然知其所以然,总结加分析一下,int类型转String类型有以下几种方式: a+"" String.valueOf(a) Integer.toString(a) 以上三种方法在实际使用过程中都是没有问题的,但是效率上还是有些许差别的,所以写个小程序来对比一下他们的效率: int a = 123456789; long start = System.currentTimeMillis(); for (int i=0;

稀疏矩阵存储格式总结+存储效率对比:COO,CSR,DIA,ELL,HYB

转载请注明出处:Bin的专栏,http://blog.csdn.net/xbinworld 稀疏矩阵是指矩阵中的元素大部分是0的矩阵,事实上,实际问题中大规模矩阵基本上都是稀疏矩阵,很多稀疏度在90%甚至99%以上.因此我们需要有高效的稀疏矩阵存储格式.本文总结几种典型的格式:COO,CSR,DIA,ELL,HYB. (1)Coordinate(COO) 这是最简单的一种格式,每一个元素需要用一个三元组来表示,分别是(行号,列号,数值),对应上图右边的一列.这种方式简单,但是记录单信息多(行列)