JSON转换效能评比-Json.NET最优
项目里有个小需求,Web API要以JSON格式传回一个巨大物件(数十MB)。在.NET裡做JSON转换,依我所知有叁种选择,JavaScriptSerializer、DataContractJsonSerializer及Json.NET。以前没有想太多,觉得JavaScriptSerializer是.NET内建的,不像Json.NET还需要另外参照Library,又不像DataContractJsonSerializer得动用Stream、Encoding处理字串,应是最方便的做法,所以不少程式都用JavaScriptSerializer处理JSON转换,长期下来除了日期格式的眉角,倒也没什么问题。
但这回在处理大型物件时,便突显出JavaScriptSerializer的效能问题。用以下的范例来重现:
程序是用前一篇序列化文章的范例修改的,一样随机产生一个2万笔资料的List
途中会先遇到一颗地雷,预设JavaScriptSerializer能处理的资料规模有上限,当资料物件大到一定程度(JSON字串超过4MB),就会发生以下错误:
Error during serialization or deserialization using the JSON JavaScriptSerializer. The length of the string exceeds the value set on the maxJsonLength property.
因此,要调整MaxJsonLength属性,很豪气地一口气设到int.MaxValue好了!
Serialization: 717ms
Deserialization: 65,844ms
Before: User1024 / 1999-03-28 / 3,749
After: User1024 / 1999-03-27 / 3,749
Pass Test: False
第二颗地雷出现了,测试的结果是False!! 这是以前提过的老问题。(DateTime经JavaScriptSerializer.Serialize()再JavaScriptSerializer.Deserialize()时会因时区标準不同,对台湾而言而产生8小时的时差,故1999-03-28 00:00:00会变成1999-03-27 16:00:00)
第叁颗雷,瞎毁? 反序列化要65秒? 而且这还不是最夸张的,若试着把List
接着来试试DataContractJsonSerializer:
DataContractJsonSerializer dcjs =
new DataContractJsonSerializer(bigList.GetType());
Stopwatch sw = new Stopwatch();
sw.Start();
//將List<User> JSON化
MemoryStream ms = new MemoryStream();
dcjs.WriteObject(ms, bigList);
ms.Flush();
string json1 = Encoding.UTF8.GetString(ms.ToArray());
sw.Stop();
Console.WriteLine("Serialization: {0:N0}ms",
sw.ElapsedMilliseconds);
sw.Reset();
sw.Start();
//由檔案字串反序列化還原回List<User>
using (FileStream stm =
new FileStream(fileName, FileMode.Open))
{
//還原後一樣取出第indexToTest筆的User顯示內容
MemoryStream ms2 =
new MemoryStream(Encoding.UTF8.GetBytes(json1));
afterDeser =
((List<User>)dcjs.ReadObject(ms2))[indexToTest].Display;
}
sw.Stop();
Console.WriteLine("Deserialization: {0:N0}ms", sw.ElapsedMilliseconds);
结果合理多了,序列化及反序化都约在0.5秒完成! 也没有发生日期转换误差。
Serialization: 459ms
Deserialization: 568ms
Before: User1024 / 2010-09-13 / 38,262
After: User1024 / 2010-09-13 / 38,262
Pass Test: True
压轴上场,请广受好评的Json.NET出来露一手:
测试成绩出炉,与DataContractJsonSerializer相比,序列化速度慢一点点,但反序列化则快了不少:
Serialization: 536ms
Deserialization: 415ms
Before: User1024 / 2007-07-11 / 5,229
After: User1024 / 2007-07-11 / 5,229
Pass Test: True
综合评量后,做个简单结论:
JavaScriptSerializer处理大型物件的效能令人髮指... (或许也是MaxJsonLength预设值不大的塬因) 而日期时间还塬后需要额外校正,看起来只适用于小型物件、没有日期型别、不想加挂Library的场合。
DataContractJsonSerializer属BCL内建,虽然使用时必须动用MemoryStream,但也等于提供加入压缩、加密或其他处理的方便管道,在某些情场下很有用。
Json.NET的转换语法最简便(直接用static方法搞定,不需要建构物件),处理效能出色,日期时间格式预设也符合常见的ISO 8601标准(即2012-12-21T00:00:00Z),跟一些Client Library较无整合问题,还支援动态物件及其他附加特色,而以往被我嫌弃的需额外下载及加入参考的缺点,现在靠NuGet已能轻松解决,对我的需求而言,荣登最佳解决方案。
PS: 如想进一步了解,Json.NET网站有完整的功能比较表,也有一分跟JavaScriptSerializer、DataContractJsonSerializer的效能评测(不过,该案例应针对Json.NET的强项调整过,Json.NET的表现好得未免太吓人 XD),还有说明文件(浏览文件后才发现Json.NET的功能跟扩充性真是踏马的多),有兴趣的朋友可以参考。
- 评论列表(网友评论仅供网友表达个人看法,并不表明本站同意其观点或证实其描述)
-
