幾個常用Json組件的性能測試


上一篇文章中我已經介紹了JsonBuilder方案的整體思路以及一個版本的雛形代碼,他現在已經是可以使用的了,但是因為是實時反射的,所以效率並不高。

鑒於幾位博友對Json轉換組件的性能有興趣,我先放幾個常用組件的測試結果以供參考。下一篇在詳細介紹JsonBuilder的優化工作

  測試用例

using System;
using System.Collections.Generic;

/// <summary> 用戶對象
/// </summary>
public class User
{
    public static User TestUser()
    {//這里我盡量構造一個看上去很復雜的對象,並且這個對象幾乎涵蓋了所有常用的類型
        User user = new User();
        user.UID = Guid.NewGuid();
        user.Birthday = new DateTime(1986, 10, 29, 18, 00, 00);
        user.IsDeleted = false;
        user.Name = "blqw";
        user.Sex = UserSex.Male;
        user.LoginHistory = new List<DateTime>();
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(8, 00, 00)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(10, 10, 10)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(12, 33, 56)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(17, 25, 18)));
        user.LoginHistory.Add(DateTime.Today.Add(new TimeSpan(23, 06, 59)));
        user.Info = new UserInfo();
        user.Info.Address = "廣東省廣州市";
        user.Info.ZipCode = 510000;
        user.Info.Phone = new Dictionary<string, string>();
        user.Info.Phone.Add("手機", "18688888888");
        user.Info.Phone.Add("電話", "82580000");
        user.Info.Phone.Add("短號", "10086");
        user.Info.Phone.Add("QQ", "21979018");
        user.Double = Double.NegativeInfinity;
        // user.Self = user; //這里是用來測試循環引用的解析情況
        return user;
    }

    public User Self { get; set; }
    //User self
    /// <summary> 唯一ID
    /// </summary>
    public Guid UID { get; set; }
    /// <summary> 用戶名稱
    /// </summary>
    public string Name { get; set; }
    /// <summary> 生日
    /// </summary>
    public DateTime Birthday { get; set; }
    /// <summary> 性別
    /// </summary>
    public UserSex Sex { get; set; }
    /// <summary> 是否刪除標記
    /// </summary>
    public bool IsDeleted { get; set; }
    /// <summary> 最近登錄記錄
    /// </summary>
    public List<DateTime> LoginHistory { get; set; }
    /// <summary> 聯系信息
    /// </summary>
    public UserInfo Info { get; set; }
    public Double Double { get; set; }
}
/// <summary> 用戶性別
/// </summary>
public enum UserSex
{
    /// <summary>/// </summary>
    Male,
    /// <summary>/// </summary>
    Female
}
/// <summary> 用戶信息
/// </summary>
public class UserInfo
{
    /// <summary> 地址
    /// </summary>
    public string Address { get; set; }
    /// <summary> 聯系方式
    /// </summary>
    public Dictionary<string, string> Phone { get; set; }
    /// <summary> 郵政編碼
    /// </summary>
    public int ZipCode { get; set; }
}
測試用例
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection.Emit;
using System.Data;
using fastJSON;
using System.IO;
using System.Threading;

namespace blqw
{
    class Program
    {


        static void Main(string[] args)
        {
            int count = 10000;
            var obj = User.TestUser();
            TestJavaScriptSerializer(count, obj);
            TestNewtonsoftJson(count, obj);
            TestJayrockJson(count, obj);
            TestFastJson(count, obj);
            TestQuickJsonBuilder(count, obj);
            TestJsonBuilder(count, obj);
        }

        //測試QuickJsonBuilder性能
        static void TestQuickJsonBuilder(int count, object obj)
        {
            Stopwatch sw = new Stopwatch();

            Console.WriteLine();
            Console.WriteLine("QuickJsonBuilder 每次" + count + " 共10次");
            for (int j = 0; j < 10; j++)
            {
                sw.Restart();
                for (int i = 0; i < count; i++)
                {
                    QuickJsonBuilder jb = new QuickJsonBuilder();
                    jb.ToJson(obj);
                }
                sw.Stop();
                Console.Write(sw.ElapsedMilliseconds + "ms | ");
            }
            Console.WriteLine();
            Console.WriteLine("結果:" + new QuickJsonBuilder().ToJson(obj));
            Console.WriteLine("==============================================");
        }
        //測試FastJson性能
        static void TestFastJson(int count, object obj)
        {
            Stopwatch sw = new Stopwatch();
            JSONParameters p = new JSONParameters();
            p.EnableAnonymousTypes
                = p.IgnoreCaseOnDeserialize
                = p.ShowReadOnlyProperties
                = p.UseEscapedUnicode
                = p.UseExtensions
                = p.UseFastGuid
                = p.UseOptimizedDatasetSchema
                = p.UseUTCDateTime
                = p.UsingGlobalTypes
                = false;
            Console.WriteLine();
            Console.WriteLine("fastJSON.NET 每次" + count + " 共10次");
            for (int j = 0; j < 10; j++)
            {
                sw.Restart();
                for (int i = 0; i < count; i++)
                {
                    fastJSON.JSON.Instance.ToJSON(obj, p);
                }
                sw.Stop();
                Console.Write(sw.ElapsedMilliseconds + "ms | ");
            }

            Console.WriteLine();
            Console.WriteLine("結果:" + fastJSON.JSON.Instance.ToJSON(obj, p));
            Console.WriteLine("==============================================");
        }
        //測試JayrockJson性能
        static void TestJayrockJson(int count, object obj)
        {
            Stopwatch sw = new Stopwatch();

            Console.WriteLine();
            Console.WriteLine("Jayrock.Json 每次" + count + " 共10次");
            for (int j = 0; j < 10; j++)
            {
                sw.Restart();
                for (int i = 0; i < count; i++)
                {
                    var writer = new Jayrock.Json.JsonTextWriter();
                    Jayrock.Json.Conversion.JsonConvert.Export(obj, writer);
                    string str = writer.ToString();
                }
                sw.Stop();
                Console.Write(sw.ElapsedMilliseconds + "ms | ");
            }
            var w = new Jayrock.Json.JsonTextWriter();
            Jayrock.Json.Conversion.JsonConvert.Export(obj, w);

            Console.WriteLine();
            Console.WriteLine("結果:" + w.ToString());
            Console.WriteLine("==============================================");
        }

        static void TestNewtonsoftJson(int count, object obj)
        {
            Stopwatch sw = new Stopwatch();

            Console.WriteLine();
            Console.WriteLine("Newtonsoft.Json 每次" + count + " 共10次");
            for (int j = 0; j < 10; j++)
            {
                sw.Restart();
                for (int i = 0; i < count; i++)
                {
                    Newtonsoft.Json.JsonConvert.SerializeObject(obj);
                }
                sw.Stop();
                Console.Write(sw.ElapsedMilliseconds + "ms | ");
            }
            var w = Newtonsoft.Json.JsonConvert.SerializeObject(obj);

            Console.WriteLine();
            Console.WriteLine("結果:" + w.ToString());
            Console.WriteLine("==============================================");
        }

        static void TestJavaScriptSerializer(int count, object obj)
        {


            Stopwatch sw = new Stopwatch();

            Console.WriteLine();
            Console.WriteLine("JavaScriptSerializer 每次" + count + " 共10次");
            for (int j = 0; j < 10; j++)
            {
                sw.Restart();
                for (int i = 0; i < count; i++)
                {
                    new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(obj);
                }
                sw.Stop();
                Console.Write(sw.ElapsedMilliseconds + "ms | ");
            }
            var w = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(obj);

            Console.WriteLine();
            Console.WriteLine("結果:" + w.ToString());
            Console.WriteLine("==============================================");
        }

        //測試JsonBuilder性能
        static void JsonBuilder(int count, object obj)
        {
            Stopwatch sw = new Stopwatch();

            Console.WriteLine();
            Console.WriteLine("QuickJsonBuilder 每次" + count + " 共10次");
            for (int j = 0; j < 10; j++)
            {
                sw.Reset();
                sw.Start();
                for (int i = 0; i < count; i++)
                {
                    JsonBuilder jb = new JsonBuilder();
                    jb.ToJsonString(obj);
                }
                sw.Stop();
                Console.Write(sw.ElapsedMilliseconds + "ms | ");
            }
            Console.WriteLine();
            Console.WriteLine("結果:" + new JsonBuilder().ToJsonString(obj));
            Console.WriteLine("==============================================");
        }

    }
}
測試代碼

  測試方案1:微軟自帶的的 JavaScriptSerializer

引用組件:System.Web.Extensions(微軟自帶了,引用下就好)

string str = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(User.TestUser());
//{"Self":null,"UID":"6f50b429-5c13-4875-a29a-e4bd8d7b2772","Name":"blqw","Birthday":"\/Date(530964000000)\/","Sex":0,"IsDeleted":false,"LoginHistory":["\/Date(1377129600000)\/","\/Date(1377137410000)\/","\/Date(1377146036000)\/","\/Date(1377163518000)\/","\/Date(1377184019000)\/"],"Info":{"Address":"廣東省廣州市","Phone":{"手機":"18688888888","電話":"82580000","短號":"10086","QQ":"21979018"},"ZipCode":510000},"Double":-Infinity}

  測試方案2:Newtonsoft.Json

引用組件:Newtonsoft.Json.Net35.dll

string str = Newtonsoft.Json.JsonConvert.SerializeObject(User.TestUser());
//{"Self":null,"UID":"6f50b429-5c13-4875-a29a-e4bd8d7b2772","Name":"blqw","Birthday":"\/Date(530964000000+0800)\/","Sex":0,"IsDeleted":false,"LoginHistory":["\/Date(1377129600000+0800)\/","\/Date(1377137410000+0800)\/","\/Date(1377146036000+0800)\/","\/Date(1377163518000+0800)\/","\/Date(1377184019000+0800)\/"],"Info":{"Address":"廣東省廣州市","Phone":{"手機":"18688888888","電話":"82580000","短號":"10086","QQ":"21979018"},"ZipCode":510000},"Double":-Infinity}

  測試方案3:Jayrock.Json

引用組件:Jayrock.Json.dll

JsonTextWriter jtw = new Jayrock.Json.JsonTextWriter();
Jayrock.Json.Conversion.JsonConvert.Export(User.TestUser(), jtw);
string str = jtw.ToString();
//{"uID":"6f50b429-5c13-4875-a29a-e4bd8d7b2772","name":"blqw","birthday":"1986-10-29T18:00:00.0000000+08:00","sex":"Male","isDeleted":false,"loginHistory":["2013-08-22T08:00:00.0000000+08:00","2013-08-22T10:10:10.0000000+08:00","2013-08-22T12:33:56.0000000+08:00","2013-08-22T17:25:18.0000000+08:00","2013-08-22T23:06:59.0000000+08:00"],"info":{"address":"廣東省廣州市","phone":{"手機":"18688888888","電話":"82580000","短號":"10086","QQ":"21979018"},"zipCode":510000},"double":-Infinity}

  測試方案4:fastJSON.NET

引用組件:fastJSON.dll

JSONParameters p = new JSONParameters();
p.EnableAnonymousTypes
    = p.IgnoreCaseOnDeserialize
    = p.ShowReadOnlyProperties
    = p.UseEscapedUnicode
    = p.UseExtensions
    = p.UseFastGuid
    = p.UseOptimizedDatasetSchema
    = p.UseUTCDateTime
    = p.UsingGlobalTypes
    = false;//所有參數為false,執行速度最快

string str = fastJSON.JSON.Instance.ToJSON(User.TestUser(), p);
//{"Self":null,"UID":"6f50b429-5c13-4875-a29a-e4bd8d7b2772","Name":"blqw","Birthday":"1986-10-29 18:00:00","Sex":"Male","IsDeleted":false,"LoginHistory":["2013-08-22 08:00:00","2013-08-22 10:10:10","2013-08-22 12:33:56","2013-08-22 17:25:18","2013-08-22 23:06:59"],"Info":{"Address":"廣東省廣州市","Phone":{"手機":"18688888888","電話":"82580000","短號":"10086","QQ":"21979018"},"ZipCode":510000},"Double":-Infinity}

  測試方案5,6:QuickJsonBuilder,JsonBuilder

ps:以上幾種類型都不支持循環引用,如果有,直接拋出異常

說明:QuickJsonBuilder就是我上篇中介紹的JsonBuilder的終極形態

QuickJsonBuilder jb = new QuickJsonBuilder();
jb.ToJson(User.TestUser());
//{"Self":null,"UID":"6f50b429-5c13-4875-a29a-e4bd8d7b2772","Name":"blqw","Birthday":"1986-10-29 18:00:00","Sex":"Male","IsDeleted":false,"LoginHistory":["2013-08-22 08:00:00","2013-08-22 10:10:10","2013-08-22 12:33:56","2013-08-22 17:25:18","2013-08-22 23:06:59"],"Info":{"Address":"廣東省廣州市","Phone":{"手機":"18688888888","電話":"82580000","短號":"10086","QQ":"21979018"},"ZipCode":510000},"Double":-Infinity}

ps:當Self指向自己本身的時候,將返回 "Self":undefined 用以區分空對象

 

  測試方案7:ServiceStack.Text

 引用組件:ServiceStack.Text.dll 抱歉我只找到4.0的 

這個是后來補上的,測試代碼中沒有這個...

User.TestUser().ToJson();
//{"UID":"48d4624ad0c8475094d00fc769c7129f","Name":"blqw","Birthday":"\/Date(530964000000+0800)\/","Sex":"Male","IsDeleted":false,"LoginHistory":["\/Date(1377129600000+0800)\/","\/Date(1377137410000+0800)\/","\/Date(1377146036000+0800)\/","\/Date(1377163518000+0800)\/","\/Date(1377184019000+0800)\/"],"Info":{"Address":"廣東省廣州市","Phone":{"手機":"18688888888","電話":"82580000","短號":"10086","QQ":"21979018"},"ZipCode":510000},"Double":-Infinity}

ps:依然不支持循環引用,拋出堆棧異常

  測試結果(單位 "毫秒")

 
循環次數 測試組件 第一輪 第二輪 第三輪 第四輪 第五輪
1次  JavaScriptSerializer  12
 0  0  0  0
 Newtonsoft.Json  208  0  0  0  0
 Jayrock.Json  85  0  0  0  0
 fastJSON.NET  47  0  0  0  0
 QuickJsonBuilder  37  0  0  0  0
 JsonBuilder  22  0  0  0  0
ServiceStack.Text  138  0  0  0  0
100次  JavaScriptSerializer  23  7  7  8  7
 Newtonsoft.Json  201  2  3  2  2
 Jayrock.Json  77  8  9  9  8
 fastJSON.NET  41  1  1  1  1
 QuickJsonBuilder  36  1  1  1  1
 JsonBuilder  26  3  4  3  3
ServiceStack.Text  139  2  2  2  2
10000次  JavaScriptSerializer  765  751  752  751  749
 Newtonsoft.Json  437  253  251  248  243
 Jayrock.Json  967  905  965  913  952
 fastJSON.NET  239  181  200  167  166
 QuickJsonBuilder  171  128  132  136  129
 JsonBuilder  418  386  388  391  360
ServiceStack.Text  367  216  224  238  223

 

 測試結果僅供參考

 

  總結

 可以看出基本所有組件在第一輪用時都是最長的,應該是在處理一些初始化和緩存的工作。

所以呢,我特別給出了1次的循環結果,

JavaScriptSerializer 可以看出在100次以內的時候微軟的還是有一些優勢的,隨着次數增加性能就漸漸跟不上了

Newtonsoft.Json一直表現平平啊,沒有特別突出就地方,就跟JsonBuilder比性能也沒有好到那里去

Jayrock.Json 是昨天一位博友告訴我的,據說是淘寶sdk在用的,性能只能說,好差。。。

fastJSON.NET 確實是所有組件中最快的,QuickJsonBuilder也從中借鑒了一些處理方式

ServiceStack.Text 中規中矩吧比Newtonsoft.Json好一點點.就是我只找到4.0的拓展方法,不知道2.0下有沒有相應的組件

好吧 我自己的組件我就不做評價了

 


免責聲明!

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



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