序列化效率比拼——誰是最后的贏家Newtonsoft.Json


      前言:作為開發人員,對象的序列化恐怕難以避免。樓主也是很早以前就接觸過序列化,可是理解都不太深刻,對於用哪種方式去做序列化更是隨波逐流——項目中原來用的什么方式照着用就好了。可是這么多年自己對於這東西還是挺模糊的,今天正好有時間,就將原來用過的幾種方式總結了下,也算是做一個記錄,順便做了下性能測試。樓主算了下,從使用序列化到現在,用到的無非下面幾種方式:(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比較強。

 

以上只是樓主自己做的簡單測試,可能存在不夠嚴謹的地方,望各位大蝦拍磚指正~~

附上源碼:源碼下載

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM