[.NET 開源] 高性能的 Swifter.MessagePack 已發布,併發布新版本的 Swifter.Json 和 Swifter.Data。

抱歉各位朋友,由於各種私事公事,本應該在 19 年底發布的 Swifter.MessagePack 庫延遲了這麼久才發布,我深感抱歉。

MsgPack 簡介

MsgPack 一種非常輕巧的二進制數據交換格式,巧妙的設計讓它相比其他二進制數據格式更可讀,並且有着不錯的壓縮率和邏輯性能,是目前相當火熱的數據交換格式。

Swifter.MessagePack 遵循 MsgPack 新的規範實現;相比 .NET 其他 MsgPack 序列化庫,Swifter.MessagePack 有着更好的性能,生成的內容更緊湊合理且更簡單易用。

Nuget:Swifter.MessagePackSwifter.JsonSwifter.Data

GitHub:Swifter.MessagePackSwifter.Json

如果您想使用 Swifter 庫,請在 Nuget 上安裝/下載最新版本,如需單文件版本,請自行生成/合併。

 

簡單使用 Swifter.MessagePack

MessagePackFormatter 類內部還有十個方法重載,包括靜態和實例方法,總有一些適合您;這些方法都是線程安全的。

更多使用方法請參考早期關於 Swifter.Json 的文章,GitHub 或 Wiki;學習交流進 Swifter 的 QQ 群:133630914(新群,歡迎加入)。

 

Swifter 框架的特性

(1) Swifter 可以運行在 .NET Framework 2.0+, .NET Core 2.0+, .NET Standard 2.0+, MONO JIT, MONO AOT, Xamarin.Android, Xamarin.iOS, Unity JIT 等平台/運行時上,Unity IL2CPP 運行時由於沒有我們測試環境,不知可否正常運行,更多信息請看下面的 AOT 說明

(2) Swifter 有着深層的抽象封裝,這雖然帶來了一些性能和內存的損耗,但也獲得了更高的擴展性;Swifter.Json/Swifter.MessagePack/Swifter.Data 的可公用的代碼非常多,這使得在 Swifter 上實現一個新的序列化庫只需要編寫少量代碼即可實現,這是其他框架難實現的。

(3) 雖然 Swifter 有很多接口和抽象編程,但是 Swifter 並沒有因此比其他的框架慢或內存佔用大,反比它們更快和更小內存佔用;這是因為 Swifter 從來都是使用更好算法和邏輯來獲取性能,而不是使用更直接的代碼獲取直接的性能。

(4) 作為類庫開發者,我們深知每個人開發和測試的側重點都與他人不一樣,自己找出自己的問題太難,所以 Swifter.Json 和 Swifter.MessagePack 除了我們自己的測試單元之外, 還 “偷” 了 Newtonsoft, Neuecc 和 Spanjson 的 5000+ 個測試單元( 去除了 Newtonsoft 的部分測試單元);現已測試通過 4200+ 個,不通過 800+ 個是我們認為可以允許或是更加合理的行為。(不勞而獲的測試單元確實用着很爽,但事實是我們”搬”這些測試單元用了 3 天,無腦替換改到手指抽筋)

 

Swifter.Json 和 Swifter.MessagePack

(1) Swifter.MessagePack 和 Swifter.Json 一樣,都有着非常優異的性能和極小的額外內存分配。

(2) Swifter.MessagePack 和 Swifter.Json 的 API 大致相同,如果使用者同時使用它們,那麼可以極小成本在它們之間切換。

(3) 得益於 Swifter.Core 的強大數據映射,Swifter.MessagePack 和 Swifter.Json 都同時支持 .NET 上大多數常用的數據結構和類型。

(4) Swifter.MessagePack 和 Swifter.Json 對重複引用的對象的表示方式不一樣,在開啟 MultiReferencingReference 配置項后,Swifter.Json 將使用 { “$ref”: “#/obj/1/target” } 來表示重複引用的對象,而 Swifter.MessagePack 使用對象在 MsgPack 內容的偏移量表示重複引用的對象;相比之下 Swifter.MessagePack 的方案更簡單性能更快,但是可讀性較差,不過說來 MsgPack 本來就是要專門的工具才能閱讀。

(5) Swifter.MessagePack 在序列化基礎類型時,在保證精度不丟失的前提下,將大數據類型轉換為更小數據類型,以得到更緊湊的 MsgPack 內容(如將 double 123 轉換為 int 123,int 123 只需要 1 個字節即可表示,如果不做轉換則需要 9 個字節表示)。

(6) Swifter.MessagePack 在序列化未知長度的集合時(如 Enumerable<T>),會將長度定義為四字節 (FixArray32),然後在寫入完成后把實際長度賦予這四字節長度;這樣雖然在較短的未知長度集合時,將產生 1-3 個 0;但是這避免了將未知長度的集合轉換為 List<T> 或 T[], 這提高了性能也減少了內存分配,這是不虧的(因為未知長度的集合很常用,如 Linq,DbDataReader 等)。

 

新版本做了啥?

(1) 主要是解決了已知 BUG,包括了 Issues 上提到的幾個。

(2) 允許將 “” 值解析為 DateTime, int?, double 等基礎類型的默認值,但是需要啟用 EmptyStringAsDefault 配置項,默認未開啟。

(3) 解決了 Swifter.Json 浮點數: float, double 失真的問題,並增加了 UseSystemFloatingPointsMethods 配置項使用系統的浮點數方法,此配置項的更多說明請看該配置項的註釋。

(4) 增加了序列化的事件:ObjectFiltering 和 ArrayFiltering,這兩個事件可以對正在序列化中的 鍵/值 做處理和篩選,包括駝峰命名法,忽略一些值等。它們被放在 JsonFormatter 和 MessagePackFormatter 的實例裏面。

(5) 增加了 .NET 對象的持久序列化和反序列化功能,這個功能將對象序列化為包含類型信息和字段值的內容,不包含邏輯信息;使用 SerializationBox<T> 盒子使用此功能。圖示:

更多新增的功能請繼續看以下內容。

 

 

AOT

在 Swifter 新版本里,AOT 的 JIT 的界限更加明顯,由 VersionDifferences.IsSupportEmit 字段標識;當這個字段為 true 表示當前平台是 JIT 運行時,Swifter 將在一些類中使用 Emit 技術提高性能;當此字段為 false 時,Swifter 會完全不使用 Emit 技術。

因我們設備有限,無法提供大規模的平台測試,但我們非常希望可以 Swifter 可以支持更多的平台,所以希望朋友們加 Swifter 交流 QQ 群:(133630914),在這裏我們可以更快的提供反饋。

 

直接文檔讀取/寫入的 API

通常情況下,將小型對象序列化為 Json/MsgPack 和將小型 Json/MsgPack 反序列化為對象是 .NET 程序中常見的操作,Swifter 也正以此為常用場景做優化,所以 Swifter 在對小型數據操作時性能最佳,且相比其他 Json/MsgPack 解析庫優勢明顯。

但在大型數據下優勢減少,這主要原因是大型數據的存儲需要實體類或字典/集合存儲,創建/填充/遍歷這些對象消耗了大量資源(接口編程的損耗);所以 Swifter 提供了直接讀取/寫入的 API 來繞開了對存儲介質的操作,以更快更小損耗的讀寫大型數據。

使用 JsonFormatter.CreateJsonReader/MessagePackFormatter.CreateMessagePackReader 函數來創建文檔讀取器,使用 JsonFormatter.CreateJsonWriter/MessagePackFormatter.CreateMessagePackWriter 函數來創建文檔寫入器。

使用文檔讀取器完整的讀取一個 Json/MsgPack 文檔將比反序列化為對象快 4-8 倍!使用文檔寫入器生成文檔的性能與將實體類序列化為 Json/MsgPack 相差較小,前提是您已構建好了這些對象。

讀取器演示:

寫入器演示:

 

擁有簡單預測數組的長度的能力

Swifter 在對小型數組,部分集合寫入時,會根據數組的類型,來源(Data,Json,MsgPack 等),名稱等信息並結合之前的一些長度記錄,簡單的預測出新的數組的長度;在寫入完成后,如果預測長度與實際長度不符,則擴展或壓縮為實際長度;如果與實際長度相符,則不需要重新創建新數組。此能力有效提高反序列化小型數組和部分集合性能,並且減少額外內存分配。

在其他高性能的 Json 解析庫,它們使用 ArrayPool<T> 同樣可以提高性能和減少內存分配;但是由於 Swifter 對兼容性的要求,使得我們不能使用 ArrayPool<T> 方案;在數組的長度比較穩定的情況下,我們的方案更好;但在數組長度非常不穩定的情況下,我們的方案可能仍需要 1-3 次的擴容/壓縮。

 

假定有序的對象反序列化

Swifter.Json 和 Swifter.MessagePack 都支持了假定有序的對象反序列化,當一個 Json/MsgPack 的對象與當前的實體類對象的字段順序一致時,將有效提升反序列化性能。

此操作默認不開啟,可以使用 AsOrderedObjectDeserialize 配置項開啟。

 

高性能的反射封裝

Swifter.Core 里提供了一些對反射封裝的類,它們放在 Swifter.Reflection 命名空間下;這些類型主要功能就是提高了系統反射的性能;XObjectRW 正是使用它們實現不依賴 Emit 的高性能對象讀寫器。

雖然放棄一些安全性檢查可以提高更多的性能,但是我們並沒有這麼做;我們仍然有類型安全檢查和防溢出檢查(事實上讀寫字段和屬性大多數的損害都在這裏,如果去掉這些檢查將得到上百倍的性能;事實上這些檢查只起到了提示程序員不能這麼做的作用,程序實際運行時這些檢查無意義)。

 

高效的数字 ToString 和 Parse 方法

Swifter.Core 提供了一些高性能数字算法,包括 Int64, UInt64, Double, Single, Decimal 的 Parse 和 ToString 算法,它們被放在 Swifter.Tools.NumberHelper 里,這些算法被應用與 Swifter.Json 和一些其他地方,這些算法支持 2-64 進制。

 

XConvert 萬能類型轉換器

Swifter.Tools.XConvert.Convert<TSource, TDestination> 是一個功能強大的萬能類型轉換函數,它在初始化時嘗試以下方式獲取合適的轉換函數:

(1) 包含在 System.Convert 里的基礎轉換函數;

(2) 類型兼容的隱式轉換(如:從子類轉換為父類,從 Int32 轉換為 Int64,從 Int64 轉換為 Double)。

(3) 原類型和目標類型中的 static implicit operator (隱式轉換) 函數。

(4) 原類型中的 ToXXX 實例函數。

(5) 目標類型中的 Parse 和 ValueOf 靜態函數。

(7) 目標類型的構造函數。

(8) 原類型和目標類型中的 static explicit operator (顯式轉換) 函數。

(9) 當以上方法都沒有找到合適函數時,將使用 (TDestination)(object)value 進行強制轉換。

簡單示例:

 

性能測試

ServiceStack.Json, Jil, LitJson, NetJson 等庫因為出錯太多未展示出來;如果有需要,您可以到 GitHub 上自行克隆/修改/運行,已收錄了 .NET 的大多數 Json 序列化庫。

 

更多實用功能等你發現…

Swifter.Core 還提供了許許多多的工具類,包括反射,委託,類型轉換,字符串,加密,哈希,数字,日期,數組和集合等工具,它們被放在 Swifter.Tools 命名空間下,您可以使用它們來提高開發效率和運行效率。

Swifter.RW 命名空間是整個 Swifter 框架的核心,它主要邏輯是:從讀取器中讀取值,寫入到寫入器中;如:從 JsonReader 讀取值到 ObjectWriter 或 DictionaryWriter 中;熟悉它們就等於精通了 Swifter 框架。

Swifter.Json/Swifter.MessagePack 有一個非常重要的配置項 JsonFormatterOptions/MessagePackFormatterOptions;使用前建議先閱讀它們,以配置更適合您系統的序列化和反序列化方案。

 

最後附上 Swifter.Data 的簡介

Swifter.Data 是一個小型的 ORM 工具,它相比 Dapper 性能要快一些,功能要強大一些。

 

感謝閱讀

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※別再煩惱如何寫文案,掌握八大原則!

網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!

※超省錢租車方案

※教你寫出一流的銷售文案?

網頁設計最專業,超強功能平台可客製化

※產品缺大量曝光嗎?你需要的是一流包裝設計!