Hprose 3.0 for .NET 的序列化為何這么快

經(jīng)過一年的開發(fā)跃须,Hprose 3.0 for .NET 的序列化反序列化部分終于基本上完成了续语。

這次升級(jí)是完全重寫了 Hprose for .NET 的代碼邀窃。

之前的 Hprose 1.x for .NET 兼容 .NET 所有的平臺(tái)版本氨菇,包括 .NET Framework 诀姚、.NET Compact Framework响牛、.NET Micro Framework、SilverLight赫段、Windows Phone呀打、Mono、.NET Core 等糯笙。

這次升級(jí)取消了對(duì)一些過時(shí)的 .NET 平臺(tái)的支持贬丛。僅保留了對(duì) .NET 3.5 Compact Framework、.NET 4.0+给涕、.NET Core 2.0+豺憔、.NETStandard 2.0(包含 Android、iOS够庙、Mac 平臺(tái))的支持恭应。

這次升級(jí)后的代碼,使用了最新版本的 C# 的語法來編寫首启,代碼在可讀性和性能上較之之前的版本都有了極大的改進(jìn)。

下面我們就來看看 Hprose 3.0 for .NET 序列化究竟有多快撤摸。

首先來看一下對(duì)象數(shù)組序列化反序列化性能對(duì)比毅桃,測(cè)試代碼為:BenchmarkObjectSerialize.cs,測(cè)試結(jié)果如下表所示:

Hprose 3.0 相對(duì)于 1.x 相比准夷,增加了對(duì) DataSet钥飞、DataTable 序列化和反序列化的支持。下面是 DataSet 序列化反序列化性能對(duì)比衫嵌,測(cè)試代碼為:BenchmarkDataSetSerialize.cs读宙,測(cè)試結(jié)果如下表所示:

從上面兩個(gè)圖表可以看出,雖然 Newton Json 的序列化反序列化性能跟 .NET 自帶的 DataContract 相比已經(jīng)高出很多楔绞,但是 Hprose 比 Newton Json 還要快 1 倍左右结闸。這是怎么做到的呢?下面我們就來詳細(xì)剖析一下酒朵。

泛型序列化器和反序列化器

在 Hprose 1.x for .NET 中桦锄,序列化和反序列化的代碼主要是在 HproseWriterHproseReader 兩個(gè)類中實(shí)現(xiàn)的。

而 Hprose 3.0 for .NET 中蔫耽,序列化和反序列化的代碼則分別放在 Hprose.IO.SerializersHprose.IO.Deserializers 兩個(gè)名稱空間下面结耀,并且定義了兩個(gè)抽象的泛型類 Serializer<T>Deserializer<T> 來負(fù)責(zé)序列化和反序列化。

每種具體的數(shù)據(jù)類型的序列化都由一個(gè)具體的序列化器來實(shí)現(xiàn),反序列化則由一個(gè)具體的反序列化器來實(shí)現(xiàn)图甜。

具體的序列化器和反序列化器通過 Serializer<T>Deserializer<T>Instance 屬性來獲得碍粥。

基本類型和幾個(gè)常用類型的序列化器、反序列化器被注冊(cè)在 SerializerDeserializer 這兩個(gè)非泛型類的靜態(tài)初始化方法中黑毅,當(dāng)它們第一次被調(diào)用時(shí)會(huì)自動(dòng)初始化嚼摩。

而對(duì)于數(shù)組、枚舉博肋、容器和自定義類型低斋,則會(huì)在泛型序列化器和反序列化器的 Instance 屬性第一次被調(diào)用時(shí)初始化。

通過這種方式匪凡,實(shí)現(xiàn)代碼不但變得更清晰易懂膊畴,而且更便于擴(kuò)展。

另外還有一個(gè)附加的好處病游,就是當(dāng)知道要序列化或反序列化的具體類型時(shí)唇跨,序列化器和反序列化器可以直接通過泛型類的 Instance 屬性獲取到,從而省去了判斷查找的時(shí)間衬衬。

序列化器和反序列化器除了直接緩存在泛型類的 Instance 屬性中以外买猖,還在非泛型的 SerializerDeserializer 類中通過 ConcurrentDictionary 靜態(tài)字段容器做了緩存。

雖然通過 ConcurrentDictionary 這種緩存方式要比直接通過泛型類的 Instance 屬性來獲取序列化器和反序列化器在速度上慢幾十納秒滋尉,但是對(duì)于無法在編譯期就能獲取到具體類型的數(shù)據(jù)來說玉控,這仍然是最快速的獲取序列化器和反序列化器的方式。

除了對(duì)序列化器和反序列化器采用了這種特化泛型類 + ConcurrentDictionary 的雙緩存模式以外狮惜,Hprose 在屬性字段存取器高诺、類型轉(zhuǎn)換器等實(shí)現(xiàn)上也采用了這種方式。

這是 Hprose 3.0 for .NET 序列化和反序列化性能提高的最主要原因之一碾篡。

通過表達(dá)式樹來存取字段和屬性

在 Hprose 1.x for .NET 中虱而,對(duì)于自定義類型的字段和屬性的存取,根據(jù)不同的平臺(tái)采用了直接反射和 Emit 生成代碼兩種方式开泽。

在 Hprose 3.0 for .NET 中牡拇,則統(tǒng)一使用了表達(dá)式樹生成代碼的方式。表達(dá)式樹生成的代碼跟使用 Emit 生成的代碼穆律,在執(zhí)行效率上是沒有差別的惠呼。但是在實(shí)現(xiàn)上,表達(dá)式樹實(shí)現(xiàn)的代碼具有更好的可讀性峦耘。

另外罢杉,對(duì)于表達(dá)式樹生成的代碼也做了雙緩沖,因此序列化反序列化自定義對(duì)象的執(zhí)行效率幾乎可以達(dá)到甚至超過硬編碼的效率贡歧。

通過表達(dá)式樹來創(chuàng)建對(duì)象

在 C# 中創(chuàng)建一個(gè)對(duì)象滩租,可以通過 new 關(guān)鍵字來創(chuàng)建赋秀,也可以通過反射的方式來創(chuàng)建。跟通過反射創(chuàng)建對(duì)象相比律想,new 一個(gè)對(duì)象顯然要快的多猎莲。

但是創(chuàng)建泛型對(duì)象是個(gè)特例。例如:

public T New<T>() where T : new() => new T();

這個(gè)方法技即,它在調(diào)用時(shí)著洼,new T() 生成的 IL 代碼實(shí)際上跟:

 Activator.CreateInstance<T>();

是差不多的。

也就是說而叼,雖然代碼中寫的是 new T()身笤,但是實(shí)際上調(diào)用的卻是 Activator.CreateInstance<T>()

Hprose 中為了更快的創(chuàng)建泛型對(duì)象葵陵,使用了下面這個(gè)泛型對(duì)象創(chuàng)建工廠:

    public static class Factory<T> {
        private static readonly Func<T> constructor = GetConstructor();
        private static Func<T> GetConstructor() {
            try {
                return Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();
            }
            catch {
                return () => (T)Activator.CreateInstance(typeof(T), true);
            }
        }
        public static T New() {
            return constructor();
        }
    }

該工廠類通過表達(dá)式樹來生成創(chuàng)建對(duì)象的代碼液荸,表達(dá)式樹生成的代碼跟直接 new 具體類型是一樣的,速度上比 Activator.CreateInstance<T>() 要快 2 - 3 倍(在 Mono 平臺(tái)上甚至?xí)鞄资叮┩迅荨V挥挟?dāng)表達(dá)式樹創(chuàng)建失敗時(shí)娇钱,才會(huì)使用 Activator.CreateInstance 作為代替方案。另外绊困,這里使用的是 Activator.CreateInstance(typeof(T), true)文搂,這樣不但在性能上比 Activator.CreateInstance<T>() 快幾納秒,而且它還可以創(chuàng)建只有非 public 無參構(gòu)造器的類的對(duì)象秤朗。

最新版本的代碼可以在 github 的 hprose/hprose-dotnet 中查看煤蹭。如果大家有更好的改進(jìn)方式,歡迎大家提交修改取视。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末硝皂,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子贫途,更是在濱河造成了極大的恐慌吧彪,老刑警劉巖待侵,帶你破解...
    沈念sama閱讀 222,000評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件丢早,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡秧倾,警方通過查閱死者的電腦和手機(jī)怨酝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,745評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來那先,“玉大人农猬,你說我怎么就攤上這事∈鄣” “怎么了斤葱?”我有些...
    開封第一講書人閱讀 168,561評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵慷垮,是天一觀的道長。 經(jīng)常有香客問我揍堕,道長料身,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,782評(píng)論 1 298
  • 正文 為了忘掉前任衩茸,我火速辦了婚禮芹血,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘楞慈。我一直安慰自己幔烛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,798評(píng)論 6 397
  • 文/花漫 我一把揭開白布囊蓝。 她就那樣靜靜地躺著饿悬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪慎颗。 梳的紋絲不亂的頭發(fā)上乡恕,一...
    開封第一講書人閱讀 52,394評(píng)論 1 310
  • 那天,我揣著相機(jī)與錄音俯萎,去河邊找鬼傲宜。 笑死,一個(gè)胖子當(dāng)著我的面吹牛夫啊,可吹牛的內(nèi)容都是我干的函卒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,952評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼撇眯,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼报嵌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起熊榛,我...
    開封第一講書人閱讀 39,852評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤锚国,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后玄坦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體血筑,經(jīng)...
    沈念sama閱讀 46,409評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,483評(píng)論 3 341
  • 正文 我和宋清朗相戀三年煎楣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了豺总。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,615評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡择懂,死狀恐怖喻喳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情困曙,我是刑警寧澤表伦,帶...
    沈念sama閱讀 36,303評(píng)論 5 350
  • 正文 年R本政府宣布谦去,位于F島的核電站,受9級(jí)特大地震影響蹦哼,放射性物質(zhì)發(fā)生泄漏哪轿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,979評(píng)論 3 334
  • 文/蒙蒙 一翔怎、第九天 我趴在偏房一處隱蔽的房頂上張望窃诉。 院中可真熱鬧,春花似錦赤套、人聲如沸飘痛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,470評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宣脉。三九已至,卻和暖如春剔氏,著一層夾襖步出監(jiān)牢的瞬間塑猖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,571評(píng)論 1 272
  • 我被黑心中介騙來泰國打工谈跛, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留羊苟,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,041評(píng)論 3 377
  • 正文 我出身青樓感憾,卻偏偏與公主長得像蜡励,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子阻桅,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,630評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 1.概述2.Gson的目標(biāo)3.Gson的性能和擴(kuò)展性4.Gson的使用者5.如何使用Gson 通過Maven來使用...
    人失格閱讀 14,265評(píng)論 2 18
  • 為了更好的學(xué)習(xí)Gson凉倚,特將Gson User Guide翻譯如下。由于本人英文水平有限嫂沉,如有錯(cuò)誤稽寒,還請(qǐng)指正,謝謝...
    WeberLisper閱讀 6,842評(píng)論 0 6
  • JAVA序列化機(jī)制的深入研究 對(duì)象序列化的最主要的用處就是在傳遞,和保存對(duì)象(object)的時(shí)候,保證對(duì)象的完整...
    時(shí)待吾閱讀 10,872評(píng)論 0 24
  • 概況 Gson是一個(gè)Java庫趟章,它可以用來把Java對(duì)象轉(zhuǎn)換為JSON表達(dá)式杏糙,也可以反過來把JSON字符串轉(zhuǎn)換成與...
    木豚閱讀 6,805評(píng)論 0 2
  • 個(gè)性化教育計(jì)劃的重點(diǎn)應(yīng)該是收集信息恩掷,向新的和有益的方向發(fā)展姑裂。
    佳佳_4eb2閱讀 110評(píng)論 0 0