天天看點

序列化 反序列化 MessagePack for C#

閱讀目錄

快速序列化元件messagepack介紹

簡介

使用

快速開始

分析器

内置的支援類型

對象序列化

datacontract相容性

序列化不可變對象(序列化構造器)

序列化回調

union

dynamic(untyped)反序列化

object 類型序列化

typeless

性能

反序列化中每個方法的性能

lz4壓縮

與protobuf,json,zeroformatter比較

擴充

messagepack for c#

回到目錄

messagepack for c#(messagepack-csharp)是用于c#的極速messagepack序列化程式,比msgpack-cli快10倍,與其他所有c#序列化程式相比,具有最好的性能。 messagepack for c#具有内置的lz4壓縮功能,可以實作超快速序列化和二進制占用空間小。 性能永遠是重要的! 可用于遊戲,分布式計算,微服務,資料存儲到redis等。支援.net, .net core, unity, xamarin。

序列化 反序列化 MessagePack for C#

從上圖我們看出messagepack for c#在性能測試中是最好的,這裡解釋一下第三個msgpack-cli是messagepack官方實作的。第一和第二都是messagepack for c#,第一項相比第二項具有稍快一點的序列化和反序列化速度,但是第二項采用了l4壓縮功能,顯著的減少了二進制的大小。在實際使用中推薦使用l4壓縮功能。

該元件已經釋出在nuget,使用指令加入項目。

<code>install-package messagepack</code>

<code>install-package messagepackanalyzer</code>

unity在此處下載下傳 https://github.com/neuecc/messagepack-csharp/releases

定義一個類添加<code>[messagepackobject]</code>特性,公共成員(屬性或者字段)添加<code>[key]</code>特性,調用<code>messagepackserializer.serialize&lt;t&gt;/deserialize&lt;t&gt;</code>進行序列化和反序列化,<code>tojson</code>可以幫我們轉儲二進制為json格式。

序列化索引将會影響該資訊在序列化資料中的位置

預設情況下特性是必須的,但是我們有方法進行改變,讓它變為不是必須的,詳情請看後面。

<code>messagepackanalyzer</code> 可以幫助我們定義對象. 如果不符合規則,那麼特性, 程式集等可以被檢測到,如果我們編譯就會出現編譯錯誤。

序列化 反序列化 MessagePack for C#

如果要允許特定類型(例如,注冊自定義類型時),請将messagepackanalyzer.json放在項目根目錄下,并将生成操作設定為<code>additionalfiles</code>(其他檔案)。

序列化 反序列化 MessagePack for C#

這是messagepackanalyzer.json内容的一個示例。

<code>[ "mynamespace.fooclass", "mynamespace.barstruct" ]</code>

這些類型可以預設序列化。

基元(int、string等等), enum, nullable&lt;&gt;, timespan, datetime, datetimeoffset, nil, guid, uri, version, stringbuilder, bitarray, arraysegment&lt;&gt;, biginteger, complext, task, array[], array[,], array[,,], array[,,,], keyvaluepair&lt;,&gt;, tuple&lt;,...&gt;, valuetuple&lt;,...&gt;, list&lt;&gt;, linkedlist&lt;&gt;, queue&lt;&gt;, stack&lt;&gt;, hashset&lt;&gt;, readonlycollection&lt;&gt;, ilist&lt;&gt;, icollection&lt;&gt;, ienumerable&lt;&gt;, dictionary&lt;,&gt;, idictionary&lt;,&gt;, sorteddictionary&lt;,&gt;, sortedlist&lt;,&gt;, ilookup&lt;,&gt;, igrouping&lt;,&gt;, observablecollection&lt;&gt;, readonlyonservablecollection&lt;&gt;, ireadonlylist&lt;&gt;, ireadonlycollection&lt;&gt;, iset&lt;&gt;, concurrentbag&lt;&gt;, concurrentqueue&lt;&gt;, concurrentstack&lt;&gt;, readonlydictionary&lt;,&gt;, ireadonlydictionary&lt;,&gt;, concurrentdictionary&lt;,&gt;, lazy&lt;&gt;, task&lt;&gt;, 自定義繼承icollection &lt;&gt;或idictionary &lt;,&gt;具有無參構造方法, ilist,idictionary和自定義繼承icollection或idictionary具有無參構造函數(包括arraylist和hashtable)。

您可以添加自定義類型的支援和一些官方/第三方擴充包。 對于immutablecollections(immutablelist &lt;&gt;等),對于reactiveproperty和unity(vector3, quaternion等等),對于f#(record,fslist,discriminated unions等)。

<code>messagepack.nil</code>是messagepack for c#的内置null/void/unit表示類型。

messagepack for c#可以序列化public class或struct,序列化目标必須标記[messagepackobject]和[key], key類型可以選擇int或字元串。如果key類型是int,則使用序列化格式為數組,如果key類型是字元串,則使用序列化格式為鍵值對,如果您定義了[messagepackobject(keyaspropertyname:true)],則不需要key特性。

所有模式序列化目标都是公共執行個體成員(字段或屬性)。 如果要避免序列化目标,可以将<code>[ignoremember]</code>添加到目标成員。

目标類必須是 public, 不允許 private, internal 類.

應該使用哪種key類型,int或string? 作者建議使用int key,因為比string key更快,更緊湊。 但是string key有關鍵的名字資訊,對調試很有用。

messagepackserializer序列化目标時,必須在目标使用特性才能保證穩健性,如果類進行了擴充,你必須意識到版本控制。如果key不存在,messagepackserializer将會使用預設值。如果使用的是int key,那麼必須從0開始,如果不必要的屬性出現,請填寫空缺的數字。重用是不好的。 此外,如果int key的跳轉數字差距太大,則會影響二進制大小。

如果你想像json.net那樣使用!不想加特性! 如果你這樣想,你可以使用無約定的解析器。

我想序列化私人成員! 預設情況下,不能序列化/反序列化私有成員。 但是你可以使用allow-private解析器來序列化私人成員。

我不需要類型,我想像binaryformatter那樣使用! 你可以使用無類型的解析器和幫助器。 請參閱typeless部分。

解析器是messagepack for c#的關鍵定制點。 詳情請見擴充部分。

您可以使用[datacontract]而不是[messagepackobject]。 如果type标記為datacontract,則可以使用[datamember]代替[key],[ignoredatamember]代替[ignoremember]。

[datamember(order = int)] 和 [key(int)]相同, [datamember(name = string)]和 [key(string)]相同. 如果使用 [datamember], 則類似于 [key(nameof(propertyname)].

使用datacontract使其成為一個共享的類庫,您不必引用messagepack for c#。 但是,它不包含在分析器或由<code>mpc.exe</code>生成的代碼中。此外,像unionattribute,messagepackformatterattribute,serializationconstructorattribute等功能不能使用。 出于這個原因,我建議您基本上使用messagepack for c#特性。

messagepack for c#支援反序列化不可變對象。 例如,這個struct可以自然地序列化/反序列化。

messagepackserializer choose constructor with the least matched argument, match index if key in integer or match name(ignore case) if key is string. if encounts messagepackdynamicobjectresolverexception: can't find matched constructor parameter you should check about this.

messagepackserializer選擇具有最少參數的構造方法,如果key是整型将比對索引或者如果key是字元串将比對名稱(忽略大小寫)。 如果遇到 <code>messagepackdynamicobjectresolverexception: can't find matched constructor parameter</code>你應該檢查一會下。

如果不能自動比對,可以通過[serializationconstructorattribute]手動指定使用構造函數。

如果對象實作了<code>imessagepackserializationcallbackreceiver</code>,則接受<code>onbeforeserialize</code>和<code>onafterdeserialize</code>序列化處理。

messagepack for c#支援序列化接口。這就像xmlinclude或protoinclude。在messagepack for c#裡叫union。unionattribute隻能附加到接口或抽象類。 它需要區分的整型key和子類型

c#7.0 type-switch是union的最佳選擇。 union被序列化為兩個長度的數組。

在抽象類中使用union,你可以像接口那樣使用。

繼承類型的序列化,在數組(或鍵值對)中是扁平化的,對于整型鍵是無關緊要的,它不能複制父類和所有的子類。

如果使用<code>messagepackserializer.deserialize&lt;object&gt;</code> 或者<code>messagepackserializer.deserialize&lt;dynamic&gt;</code>,messagepack将轉換為 primitive values,msgpack-primitive将轉換為<code>bool, char, sbyte, byte, short, int, long, ushort, uint, ulong, float, double, datetime, string, byte[], object[], idictionary&lt;object, object&gt;</code>.

是以你可以使用索引通路鍵值對或者數組。

<code>standardresolver</code>和<code>contractlessstandardresolver</code>可以通過<code>dynamicobjecttypefallbackresolver</code>将object類型序列化為具體類型。

unity支援是有限的。

反序列化時,與dynamic(untyped)反序列化相同。

typeless api就像binaryformatter, 将類型資訊嵌入到二進制中,是以不需要類型去反序列化.

類型資訊由mspgack ext格式序列化,typecode為100。

<code>messagepackserializer.typeless</code>是<code>serialize / deserialize &lt;object&gt;(typelesscontractlessstandardresolver.instance)</code>的快捷方式。 如果要配置預設的typeless解析器,可以通過<code>messagepackserializer.typeless.registerdefaultresolver</code>進行設定。

與其他序列化器在windows 10 pro x64 intel core i7-6700k 4.00ghz, 32gb ram上進行benchmarks比較,benchmark代碼在這-版本資訊,zeroformatter和flatbuffers具有非常快速的反序列化器,是以忽略反序列化的性能。

序列化 反序列化 MessagePack for C#

messagepack for c#使用許多技術來提高性能。

序列化隻使用ref byte []和int offset,不使用(memory)stream(調用stream api會有開銷)

進階api使用内部記憶體池,配置設定工作記憶體不要低于64k

不建立中間實用程式執行個體(xxxwriter / reader,xxxcontext等)

所有代碼避免裝箱,所有平台(包括unity / il2cpp)

對靜态泛型字段生成的格式化程式進行緩存,查找時從緩存查找(不使用字典緩存,因為字典查找需要一定開銷)

重新調整的動态代碼生成

當代碼生成知道目标是primitive時直接調用primitiveapi

當代碼生成知道目标(整數/字元串)範圍時,減少可變長度格式的分支

不在疊代集合上使用ienumerable&lt;t&gt; 抽象

使用預先生成的查找表來減少檢查消息包類型所耗時間

對非泛型方法使用優化類型key字典

避免查找映射(字元串鍵)鍵的字元串鍵解碼,并使用自動化名稱查找與il内聯代碼生成

對于字元串鍵編碼,預先生成的成員名位元組并在il中使用固定大小的二進制副本

在建立這個庫之前,作則實作了一個具有zeroformatter#performance的快速序列化器。 這是一個進一步演變的實作。 messagepack for c#始終是快速的,為所有類型(原始,小結構,大對象,任何集合)進行了優化。

性能取決于選項。 這是一個benchmarkdotnet的微型benchamark。 目标對象有9個成員(myproperty1〜myproperty9),值為零。

method

mean

error

scaled

gen 0

allocated

intkey

72.67 ns

na

1.00

0.0132

56 b

stringkey

217.95 ns

3.00

0.0131

typeless_intkey

176.71 ns

2.43

typeless_stringkey

378.64 ns

5.21

0.0129

msgpackclimap

1,355.26 ns

18.65

0.1431

608 b

msgpackcliarray

455.28 ns

6.26

0.0415

176 b

protobufnet

265.85 ns

3.66

0.0319

136 b

hyperion

366.47 ns

5.04

0.0949

400 b

jsonnetstring

2,783.39 ns

38.30

0.6790

2864 b

jsonnetstreamreader

3,297.90 ns

45.38

1.4267

6000 b

jilstring

553.65 ns

7.62

0.0362

152 b

jilstreamreader

1,408.46 ns

19.38

0.8450

3552 b

intkey,stringkey,typeless_intkey,typeless_stringkey都是messagepack for c#的方法

,在反序列化過程中實作零記憶體配置設定。jsonnetstring /jilstring從字元串反序列化。jsonststreamreader / jilstreamreader是從streamreader的utf8 byte []中反序列化的。反序列化通常從stream讀取。 是以,它将從位元組數組(或流)而不是字元串中讀取。

messagepack for c#intkey是最快的。 stringkey比intkey慢,因為stringkey需要從字元串進行比對。 如果是intkey,讀取數組長度,根據數組長度進行for循環二進制解碼。 如果stringkey,讀取map 長度,根據map長度循環,首先需要對密鑰解碼,然後按照key查找,最後二進制解碼,則需要額外兩個步驟(解碼密鑰和按鍵查找)。

字元串鍵通常是有用的,無限制的,簡單的json替換,與其他語言的互操作性,以及更多的某些版本。 messagepack for c#也為string key進行了優化。 首先,它不會将utf8位元組數組解碼為與成員名稱比對的字元串,它會按原樣查找位元組數組(避免解碼成本和額外配置設定)。

它會嘗試比對每個長整型(long)(每8個字元,如果長度不夠,填充0)使用automata和在生成時内聯il代碼。

序列化 反序列化 MessagePack for C#

這也避免了計算位元組數組的哈希碼,并且可以在長單元上進行多次比較。

這是ilspy生成的反序列化器代碼的示例的反編譯。

序列化 反序列化 MessagePack for C#

https://github.com/neuecc/messagepack-csharp#performance

如果節點數量很大,則使用嵌入式二進制搜尋進行搜尋。

另外請注意,這是序列化的基準測試結果。

84.11 ns

0.0094

40 b

126.75 ns

1.51

0.0341

144 b

183.31 ns

2.18

0.0265

112 b

193.95 ns

2.31

0.0513

216 b

967.68 ns

11.51

0.1297

552 b

284.20 ns

3.38

0.1006

424 b

176.43 ns

2.10

0.0665

280 b

280.14 ns

3.33

0.1674

704 b

zeroformatter

149.95 ns

1.78

0.1009

1,432.55 ns

17.03

0.4616

1944 b

jsonnetstreamwriter

1,775.72 ns

21.11

1.5526

6522 b

547.51 ns

6.51

0.3481

1464 b

jilstreamwriter

778.78 ns

9.26

1.4448

6066 b

當然,intkey是最快的,但stringkey也不錯。

messagepack是一個快速和緊湊的格式,但它不是壓縮格式。 lz4是非常快速的壓縮算法,使用messagepack for c#可以實作極快的性能和非常緊湊的二進制大小!

messagepack for c#具有内置的lz4支援。 您可以使用lz4messagepackserializer而不是messagepackserializer。 内建支援是特殊的,作者已經建立了序列化壓縮管道,并專門調整了管道,是以共享工作記憶體,不配置設定,不要調整,直到完成。

序列化二進制不是簡單地壓縮lz4二進制。 序列化二進制是有效的messagepack二進制使用ext格式和自定義typecode(99)。

protbuf-net是.net上最常用的二進制格式化庫。 我(作者)喜歡protobuf-net,并尊重那偉大的工作。 但是如果使用protobuf-net作為通用序列化格式,則可能會引起煩人的問題。

protobuf(-net)不能正确處理null和空集合。 因為protobuf沒有null表示(這是protobuf-net作者的答案)。

messagepack規範可以完全序列化c#類型。 這就是推薦messagepack而不是protobuf的原因。

protocol buffers具有良好的idl和grpc,這比messagepack好得多。 如果你想使用idl,我(作者)推薦google.protobuf。

json是很好的通用格式。 這是完美的,簡單的,足夠規範的。 utf8json建立了我采用與messagepack for c#相同的體系結構,并避免編碼/修飾成本,是以像二進制一樣工作。 如果你想了解二進制與文本,請參閱utf8json /應使用哪個序列化器部分。

zeroformatter與flatbuffers類似,但專門用于c#。 這是特别的。 反序列化速度非常快,但是二進制大小卻很大。 而zeroformatter的緩存算法需要額外的記憶體。

zeroformatter也是特别的。 當與zeroformatter對比的情況下,它顯示格式化的力量。 但是對于許多常見的用途,messagepack for c#會更好。

messagepack for c#具有擴充點,您可以添加外部類型的序列化支援。 下列是官方擴充支援。

<code>messagepack.immutablecollection</code>添加對 <code>system.collections.immutable</code>的支援. 添加了對<code>immutablearray&lt;&gt;, immutablelist&lt;&gt;, immutabledictionary&lt;,&gt;, immutablehashset&lt;&gt;, immutablesorteddictionary&lt;,&gt;, immutablesortedset&lt;&gt;, immutablequeue&lt;&gt;, immutablestack&lt;&gt;, iimmutablelist&lt;&gt;, iimmutabledictionary&lt;,&gt;, iimmutablequeue&lt;&gt;, iimmutableset&lt;&gt;, iimmutablestack&lt;&gt;</code>的序列化支援.

messagepack.reactiveproperty包添加對reactiveproperty庫的支援。它增加了<code>reactiveproperty &lt;&gt;,ireactiveproperty &lt;&gt;,ireadonlyreactiveproperty &lt;&gt;,reactivecollection &lt;&gt;,unit</code>序列化支援。 這對儲存視圖模型狀态很有用。

messagepack.aspnetcoremvcformatter是asp.net core mvc序列化的附加元件,可提升性能。 這是配置示例。

更多資訊請通路github: https://github.com/neuecc/messagepack-csharp

序列化 反序列化 MessagePack for C#
序列化 反序列化 MessagePack for C#
序列化 反序列化 MessagePack for C#
序列化 反序列化 MessagePack for C#
序列化 反序列化 MessagePack for C#
序列化 反序列化 MessagePack for C#