序列化效率比拼——谁是最后的赢家Newtonsoft.Json_weixin_33852020的博客-程序员宅基地

技术标签: json  runtime  

      前言:作为开发人员,对象的序列化恐怕难以避免。楼主也是很早以前就接触过序列化,可是理解都不太深刻,对于用哪种方式去做序列化更是随波逐流——项目中原来用的什么方式照着用就好了。可是这么多年自己对于这东西还是挺模糊的,今天正好有时间,就将原来用过的几种方式总结了下,也算是做一个记录,顺便做了下性能测试。楼主算了下,从使用序列化到现在,用到的无非下面几种方式:(1)JavaScriptSerializer方式;(2)DataContract方式;(3)Newtonsoft.Json.

1、准备工作:要对这三种方式分别作测试,必须要将相应的内库引用进来。

(1)JavaScriptSerializer这个类是.Net内置的,属于System.Web.Script.Serialization这个命名空间下面。需要引用System.Web.Extensions这个dll。

(2)DataContract方式也是.net内置的,主要使用的DataContractJsonSerializer这个类,属于System.Runtime.Serialization.Json这个命名空间。需要引用System.Runtime.Serialization这个dll。

(3)Newtonsoft.Json是第三方的dll,但是Visual Studio 对它做了很好的支持。使用方式有两种:一种是去网上下载最新的dll,然后添加引用即可;第二种是直接使用NuGet安装这个包。方式如下:

按照步骤安装即可。

 

2、类库准备完毕,还需要提供几个通用的方法。自己分别封装了JavaScriptSerializer和DataContract方式两个方法,代码如下:

    #region DataContract序列化
    public static class DataContractExtensions
    {
        /// <summary>
        /// 将对象转化为Json字符串
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="instanse">对象本身</param>
        /// <returns>JSON字符串</returns>
        public static string ToJsonString<T>(this T instanse)
        {
            try
            {
                DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T));
                using (MemoryStream ms = new MemoryStream())
                {
                    js.WriteObject(ms, instanse);
                    ms.Flush();
                    ms.Seek(0, SeekOrigin.Begin);
                    StreamReader sr = new StreamReader(ms);
                    return sr.ReadToEnd();
                }
            }
            catch
            {
                return String.Empty;
            }
        }

        /// <summary>
        /// 将字符串转化为JSON对象,如果转换失败,返回default(T)
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="s">字符串</param>
        /// <returns>转换值</returns>
        public static T ToJsonObject<T>(this string s)
        {
            try
            {
                DataContractJsonSerializer js = new DataContractJsonSerializer(typeof(T));
                using (MemoryStream ms = new MemoryStream())
                {
                    StreamWriter sw = new StreamWriter(ms);
                    sw.Write(s);
                    sw.Flush();
                    ms.Seek(0, SeekOrigin.Begin);
                    return (T)js.ReadObject(ms);
                }
            }
            catch
            {
                return default(T);
            }
        }
    } 
    #endregion

    #region JavaScriptSerializer方式序列化
    public static class JavascriptExtentions
    {
        public static string ToScriptJsonString<T>(this T instanse)
        {
            try
            {
                JavaScriptSerializer js = new JavaScriptSerializer();
                return js.Serialize(instanse);
            }
            catch
            {
                return String.Empty;
            }
        }

        public static T ToScriptJsonObject<T>(this string s)
        {
            try
            {
                JavaScriptSerializer js = new JavaScriptSerializer();
                return js.Deserialize<T>(s);
            }
            catch
            {
                return default(T);
            }
        }
    } 
    #endregion

至于Newtonsoft.Json,自己有对应的方法,自己也封装了几个方法:

public class Newtonsoft_Common
    {
        #region 序列化
        // 将对象(包含集合对象)序列化为Json
        public static string SerializeObjToJson(object obj)
        {
            string strRes = string.Empty;
            try
            {
                strRes = JsonConvert.SerializeObject(obj);
            }
            catch 
            { }

            return strRes;
        }

        //将xml转换为json
        public static string SerializeXmlToJson(System.Xml.XmlNode node)
        {
            string strRes = string.Empty;
            try
            {
                strRes = JsonConvert.SerializeXmlNode(node);
            }
            catch
            { }

            return strRes;
        }

        //支持Linq格式的xml转换
        public static string SerializeXmlToJson(System.Xml.Linq.XNode node)
        {
            string strRes = string.Empty;
            try
            {
                strRes = JsonConvert.SerializeXNode(node);
            }
            catch
            { }

            return strRes;
        }
        #endregion

        #region 反序列化
        //将json反序列化为实体对象(包含DataTable和List<>集合对象)
        public static T DeserializeJsonToObj<T>(string strJson)
        {
            T oRes = default(T);
            try
            {
                oRes = JsonConvert.DeserializeObject<T>(strJson);
            }
            catch 
            { }

            return oRes;
        }

        //将Json数组转换为实体集合
        public static List<T> JsonLstToObjs<T>(List<string> lstJson)
        {
            List<T> lstRes = new List<T>();
            try
            {
                foreach (var strObj in lstJson)
                {
                    //将json反序列化为对象
                    var oRes = JsonConvert.DeserializeObject<T>(strObj);
                    lstRes.Add(oRes);
                }
            }
            catch 
            { }

            return lstRes;
        }
        #endregion
    }

 

 

还有就是提供测试数据的两个方法:

public static List<Person> GetPersons()
        {
            var lstRes = new List<Person>();
            for (var i = 0; i < 50000; i++)
            {
                var oPerson = new Person();

                oPerson.Name = "李雷" + i;
                oPerson.Age = 20;
                oPerson.IsChild = i % 5 == 0 ? true : false;
                oPerson.Test1 = "aaaaaa";
                oPerson.Test2 = i.ToString() ;
                oPerson.Test3 = i.ToString();
                oPerson.Test4 = i.ToString();
                oPerson.Test5 = i.ToString();
                oPerson.Test6 = i.ToString();
                oPerson.Test7 = i.ToString();
                oPerson.Test8 = i.ToString();
                oPerson.Test9 = i.ToString();
                oPerson.Test10 = i.ToString();
                lstRes.Add(oPerson);
            }

            return lstRes;
        }

        public static DataTable GetDataTable()
        {
            var dt = new DataTable("dt");
            dt.Columns.Add("Age", Type.GetType("System.Int32"));
            dt.Columns.Add("Name", Type.GetType("System.String"));
            dt.Columns.Add("Sex", Type.GetType("System.String"));
            dt.Columns.Add("IsChild", Type.GetType("System.Boolean"));
            for (var i = 0; i < 1000; i++)
            {
                DataRow dr = dt.NewRow();
                dr["Age"] = i + 1;
                dr["Name"] = "Name" + i;
                dr["Sex"] = i % 2 == 0 ? "" : "";
                dr["IsChild"] = i % 5 > 0 ? true : false;
                dt.Rows.Add(dr);
            }

            return dt;
        }
View Code

 

3、测试开始之前,先介绍下,本篇测试分别通过强类型对象和若类型的DataTable分别去做序列化和反序列化的测试。测试代码:

static void Main(string[] args)
        {
            #region 强类型对象
            var lstRes = GetPersons();
            #region JavaScriptSerializer序列化方式
            var lstScriptSerializeObj = new List<string>();
            Stopwatch sp_script = new Stopwatch();
            sp_script.Start();
            foreach (var oPerson in lstRes)
            {
                lstScriptSerializeObj.Add(oPerson.ToScriptJsonString<Person>());
            }
            sp_script.Stop();
            Console.WriteLine("JavaScriptSerializer序列化方式序列化" + lstScriptSerializeObj.Count + "个对象耗时:" + sp_script.ElapsedMilliseconds + "毫秒");

            lstRes.Clear();
            Stopwatch sp_script1 = new Stopwatch();
            sp_script1.Start();
            foreach (var oFrameSerializeObj in lstScriptSerializeObj)
            {
                lstRes.Add(oFrameSerializeObj.ToScriptJsonObject<Person>());
            }
            sp_script1.Stop();
            Console.WriteLine("JavaScriptSerializer序列化方式反序列化" + lstScriptSerializeObj.Count + "个对象耗时:" + sp_script1.ElapsedMilliseconds + "毫秒");
            #endregion

            #region DataContract序列化方式
            var lstFrameSerializeObj = new List<string>();
            Stopwatch sp = new Stopwatch();
            sp.Start();
            foreach (var oPerson in lstRes)
            {
                lstFrameSerializeObj.Add(oPerson.ToJsonString<Person>());
            }
            sp.Stop();
            Console.WriteLine("DataContract序列化方式序列化" + lstFrameSerializeObj.Count + "个对象耗时:" + sp.ElapsedMilliseconds + "毫秒");

            lstRes.Clear();
            Stopwatch sp1 = new Stopwatch();
            sp1.Start();
            foreach (var oFrameSerializeObj in lstFrameSerializeObj)
            {
                lstRes.Add(oFrameSerializeObj.ToJsonObject<Person>());
            }
            sp1.Stop();
            Console.WriteLine("DataContract序列化方式反序列化" + lstFrameSerializeObj.Count + "个对象耗时:" + sp1.ElapsedMilliseconds + "毫秒"); 
            #endregion

            #region Newtonsoft
            var lstNewtonsoftSerialize = new List<string>();
            Stopwatch sp2 = new Stopwatch();
            sp2.Start();
            foreach (var oPerson in lstRes)
            {
                lstNewtonsoftSerialize.Add(JsonConvert.SerializeObject(oPerson));
            }
            sp2.Stop();
            Console.WriteLine("Newtonsoft.Json方式序列化" + lstNewtonsoftSerialize.Count + "个对象耗时:" + sp2.ElapsedMilliseconds + "毫秒");

            lstRes.Clear();
            Stopwatch sp3 = new Stopwatch();
            sp3.Start();
            foreach (var oNewtonsoft in lstNewtonsoftSerialize)
            {
                lstRes.Add(JsonConvert.DeserializeObject<Person>(oNewtonsoft));
            }
            sp3.Stop();
            Console.WriteLine("Newtonsoft.Json方式反序列化" + lstNewtonsoftSerialize.Count + "个对象耗时:" + sp3.ElapsedMilliseconds + "毫秒"); 
            #endregion
            #endregion

            #region 弱类型DataTable
            /*var dt = GetDataTable();
            #region JavaScriptSerializer序列化方式
            var lstScriptSerializeObj = new List<string>();
            Stopwatch sp_script = new Stopwatch();
            sp_script.Start();
            var strRes = dt.ToScriptJsonString<DataTable>();
            sp_script.Stop();
            Console.WriteLine("JavaScriptSerializer序列化方式序列化" + lstScriptSerializeObj.Count + "个对象耗时:" + sp_script.ElapsedMilliseconds + "毫秒");

            dt.Clear();
            Stopwatch sp_script1 = new Stopwatch();
            sp_script1.Start();
            dt = strRes.ToScriptJsonObject<DataTable>();
            sp_script1.Stop();
            Console.WriteLine("JavaScriptSerializer序列化方式反序列化" + lstScriptSerializeObj.Count + "个对象耗时:" + sp_script1.ElapsedMilliseconds + "毫秒");
            #endregion

            #region DataContract序列化方式
            var lstFrameSerializeObj = new List<string>();
            Stopwatch sp = new Stopwatch();
            sp.Start();
            strRes = dt.ToJsonString<DataTable>();
            sp.Stop();
            Console.WriteLine("DataContract序列化方式序列化" + lstFrameSerializeObj.Count + "个对象耗时:" + sp.ElapsedMilliseconds + "毫秒");

            dt.Clear();
            Stopwatch sp1 = new Stopwatch();
            sp1.Start();
            dt = strRes.ToJsonObject<DataTable>();
            sp1.Stop();
            Console.WriteLine("DataContract序列化方式反序列化" + lstFrameSerializeObj.Count + "个对象耗时:" + sp1.ElapsedMilliseconds + "毫秒");
            #endregion

            #region Newtonsoft
            var lstNewtonsoftSerialize = new List<string>();
            Stopwatch sp2 = new Stopwatch();
            sp2.Start();
            strRes = JsonConvert.SerializeObject(dt);
            sp2.Stop();
            Console.WriteLine("Newtonsoft.Json方式序列化" + lstNewtonsoftSerialize.Count + "个对象耗时:" + sp2.ElapsedMilliseconds + "毫秒");

            dt.Clear();
            Stopwatch sp3 = new Stopwatch();
            sp3.Start();
            dt = JsonConvert.DeserializeObject<DataTable>(strRes);
            sp3.Stop();
            Console.WriteLine("Newtonsoft.Json方式反序列化" + lstNewtonsoftSerialize.Count + "个对象耗时:" + sp3.ElapsedMilliseconds + "毫秒");
            #endregion*/
            #endregion

            Console.ReadLine();
        }
View Code

 

4、测试结果:

先说强类型对象的结果:

(1)集合数量100和1000时,序列化和反序列化三种方式差别不大:

(2)当超过10000时,

(3)继续加大数据量

 

 

弱类型DataTable的测试结果:

JavaScriptSerializer方式直接报错:

DataContract方式需要提供DataTable的表名,序列化得到是DataTable的Xml

 

Newtonsoft.Json方式可以实现和Json数据的序列化和反序列化。

 

5、测试总结:

(1)总的来说,DataContract和Newtonsoft.Json这两种方式效率差别不大,随着数量的增加JavaScriptSerializer的效率相对来说会低些。

(2)对于DataTable的序列化,如果要使用json数据通信,使用Newtonsoft.Json更合适,如果是用xml做持久化,使用DataContract合适。

(3)随着数量的增加JavaScriptSerializer序列化效率越来越低,反序列化和其他两种相差不大。

(4)后来发现当对象的DataTime类型属性不赋值时,DataContract和JavaScriptSerializer这两种方式序列化都会报错,而用Newtonsoft.Json方式可以正常序列化。所以看来在容错方便,还是Newtonsoft.Json比较强。

 

以上只是楼主自己做的简单测试,可能存在不够严谨的地方,望各位大虾拍砖指正~~

附上源码:源码下载

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_33852020/article/details/85736645

智能推荐

PV操作 解析_kiven.evn的博客-程序员宅基地

在说pv操作之前, 首先了解下什么是临界区   临界区  :  并发进程中和共享变量有关的程序段 。如PIN和POUT这两个并发进程的临界区 分别是:PIN 的临界区    R1:=count;R1:=R1+1;Count:=R1+1; POUT的临界区是: R2:=count;R2:=R2-1;Count:=R2+1;有

windows 修改指定文件的访问控制列表命令 icacls_hjhcos的博客-程序员宅基地

显示或修改指定文件上的随机访问控制列表 (DACL),并将存储的 DACL 应用于指定目录中的文件。icacls &lt;filename&gt; [/grant[:r] &lt;sid&gt;:&lt;perm&gt;[...]] [/deny &lt;sid&gt;:&lt;perm&gt;[...]] [/remove[:g|:d]] &lt;sid&gt;[...]] [/t] [/c] [/l] [/q] [/setintegritylevel &lt;Level&gt;:&lt;policy&

kylin调优,项目中错误总结,知识点总结,kylin jdbc driver + 数据库连接池druid + Mybatis项目中的整合,shell脚本执行kylin restapi 案例_乖乖猪001的博客-程序员宅基地

关于本篇文章的说明:本篇文章为笔者辛苦劳作用了一整天总结出来的文档,大家阅读转发的时候请不要吝啬写上笔者:涂作权 和 原文地址。由于笔者所在环境没有人用过kylin,笔者也是自学官网,阅读书籍 将kylin用于实际项目,期间遇到了很多很多关于kylin使用的问题。为了让后面的人在使用kylin实践的时候能够少走弯路,在此生成kylin的调优,错误...

Java回调函数实例_88小子的博客-程序员宅基地_java回调函数例子

回调函数简单点说就是:A调用B中的方法,B方法执行结束后,再调用A中的方法,而该方法就是回调函数。下面举个例子,该例子的主要思想是:A打电话给B,叫B帮忙买东西,B会给A回电话东西是否买到了。 接口类:Callback.javapackage lifeixu.com.callback;public interface Callback { //回调函数,A调用B的方法,B开始执行,B执行结

Spring源码重头再学习(三)---三级缓存和循环依赖源码阅读分析_redbean1993的博客-程序员宅基地

看过前两篇文章,并且自己跟过源码的同学, 应该对IOC创建bean的过程至少有了一个了解。 今天我们主要来看看Spring的三级缓存和循环依赖的解决。话不多说,咱们直接看看什么是三级缓存。 这是Spring容器getBean的时候,从缓存中获取bean的方法。这里3个缓存都已经被我圈出来,分别是以下3个map,且一级缓存是ConcurrentHashmap,当然是考虑线程安全。 那么,光这么看,好像也看不出什么名堂,我们要带着问题来看,这3个缓存分别在什么时候被用到,为什么...

springboot 之 elasticsearch + mybatis 组件化开发_架构路上的博客-程序员宅基地

进行自动装配两种方式:使用自定义注解自定义注解 @EnableKnowledge导入真正的配置类引用模块在启动类或者其他spring管理的bean上添加注解@[email protected]({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@[email protected](ElasticSearchConfig.class)public @interface EnableKnowledge {}

随便推点

揭秘webpack插件工作流程和原理_请叫我小一的博客-程序员宅基地

前言通过插件我们可以扩展webpack,在合适的时机通过Webpack提供的 API 改变输出结果,使webpack可以执行更广泛的任务,拥有更强的构建能力。 本文将尝试探索webpack插件的工作流程,进而去揭秘它的工作原理。同时需要你对webpack底层和构建流程的一些东西有一定的了解。想要了解 webpack 的插件的机制,需要弄明白以下几个知识点: 一个简单的插件的构成 webpack构建流程 Tapable是如何把各个插件串联到一起的 compile..

python os.path.splitext()的用法_你应该使用pathlib替代os.path_weixin_39633113的博客-程序员宅基地

原标题:你应该使用pathlib替代os.path在Python 3.4之前和路径相关操作函数都放在os模块里面,尤其是 os.path这个子模块,可以说 os.path模块非常常用。而在Python 3.4,标准库添加了新的模块 - pathlib,它使用面向对象的编程方式来表示文件系统路径。作为一个从Python 2时代过来的人,已经非常习惯使用os,那么为什么我说「应该使用pathlib替代...

Android系统导入电话簿,将黑莓手机的电话簿导入安卓系统_码字的刺猬的博客-程序员宅基地

第一步:1. 首先打开桌面管理器并连接至黑莓手机;2. 打开电脑里的outlook;3. 黑莓桌面管理器先打开管理器选项,进入页面后出现了一个【选择需要同步管理器数据】的页面;4. 设置桌面管理器,在上述页面里在通讯录里是不能划对号的,只能通过下面的设置 顺序---配置设置---勾选通讯录---选择微软outlook选项点下一步---双向同步(点选)下一步---点选使用现有“主标识完成”字样;5....

hdu3342 Legal or Not---拓扑排序_wust_tanyao的博客-程序员宅基地

1、所有in=0的都拿出去了,但vis还不全为0,则一定有环拓扑排序:用邻接表存储比较方便1、找到一个入度为0的点,删除它,它的所有后继结点入度-12、重复1知道没有入度为0的点存在,这时所有删除的顶点构成一个全序关系。#include #include #include #include #include #include #include #inc

mysql报错mysqld_safe Number of processes running now: 0_TURING.DT的博客-程序员宅基地

mysql自动shutdown,查看mysql的日志发现如下内容:160504 15:39:11 [Note] /usr/local/mysql/bin/mysqld (mysqld 5.5.46-log) starting as process 82685 ...160504 15:39:11 [Warning] Changed limits: max_open_files: 1024 

Web2.0设计师工具箱,国外的一些网站制作资源,css,javascript,ajax,设计素材等_Monster_ll的博客-程序员宅基地

http://hi.baidu.com/sw%5Fws/blog/item/32b4237e63bbf13b0cd7da83.html   Web2.0工具箱 The Web Designers Tool Kit原文地址: http://www.dezinerfolio.com/2007 ... designers-tool-kit/分类一、DHTML AJAX Javascrip