日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

快速序列化组件MessagePack介绍

發(fā)布時(shí)間:2023/12/4 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 快速序列化组件MessagePack介绍 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

簡(jiǎn)介

MessagePack for C#(MessagePack-CSharp)是用于C#的極速M(fèi)essagePack序列化程序,比MsgPack-Cli快10倍,與其他所有C#序列化程序相比,具有最好的性能。 MessagePack for C#具有內(nèi)置的LZ4壓縮功能,可以實(shí)現(xiàn)超快速序列化和二進(jìn)制占用空間小。 性能永遠(yuǎn)是重要的! 可用于游戲,分布式計(jì)算,微服務(wù),數(shù)據(jù)存儲(chǔ)到Redis等。支持.NET, .NET Core, Unity, Xamarin。

從上圖我們看出MessagePack for C#在性能測(cè)試中是最好的,這里解釋一下第三個(gè)MsgPack-Cli是MessagePack官方實(shí)現(xiàn)的。第一和第二都是MessagePack for C#,第一項(xiàng)相比第二項(xiàng)具有稍快一點(diǎn)的序列化和反序列化速度,但是第二項(xiàng)采用了L4壓縮功能,顯著的減少了二進(jìn)制的大小。在實(shí)際使用中推薦使用L4壓縮功能。

使用

該組件已經(jīng)發(fā)布在Nuget,使用命令加入項(xiàng)目。

Install-Package MessagePack

分析器

Install-Package MessagePackAnalyzer

擴(kuò)展

Install-Package MessagePack.ImmutableCollection Install-Package MessagePack.ReactiveProperty Install-Package MessagePack.UnityShims Install-Package MessagePack.AspNetCoreMvcFormatter

Unity在此處下載?https://github.com/neuecc/MessagePack-CSharp/releases

快速開始

定義一個(gè)類添加[MessagePackObject]特性,公共成員(屬性或者字段)添加[Key]特性,調(diào)用MessagePackSerializer.Serialize<T>/Deserialize<T>進(jìn)行序列化和反序列化,ToJson可以幫我們轉(zhuǎn)儲(chǔ)二進(jìn)制為json格式。

// 標(biāo)記 MessagePackObjectAttribute[MessagePackObject]
public class MyClass{ ? ?// Key 是序列化索引,對(duì)于版本控制非常重要。[Key(0)] ?
?public int Age { get; set; }[Key(1)] ?
?public string FirstName { get; set; }[Key(2)] ?
??public string LastName { get; set; } ? ?// 公共成員中不序列化目標(biāo),標(biāo)記IgnoreMemberAttribute[IgnoreMember] ? ?public string FullName { get { return FirstName + LastName; } } }class Program{ ?
?static void Main(string[] args) ? ?{ ? ? ?
?var mc = new MyClass{Age = 99,FirstName = "hoge",LastName = "huga",}; ? ? ? ?// 序列化var bytes = MessagePackSerializer.Serialize(mc); ? ? ? ?//反序列化var mc2 = MessagePackSerializer.Deserialize<MyClass>(bytes); ? ? ? ?// 你可以將msgpack二進(jìn)制轉(zhuǎn)儲(chǔ)為可讀的json。// 在默認(rèn)情況下,MeesagePack for C#減少了屬性名稱信息。// [99,"hoge","huga"]var json = MessagePackSerializer.ToJson(bytes);Console.WriteLine(json);Console.ReadKey();} }

序列化索引將會(huì)影響該信息在序列化數(shù)據(jù)中的位置

默認(rèn)情況下特性是必須的,但是我們有方法進(jìn)行改變,讓它變?yōu)椴皇潜仨毜?#xff0c;詳情請(qǐng)看后面。

分析器

MessagePackAnalyzer?可以幫助我們定義對(duì)象. 如果不符合規(guī)則,那么特性, 程序集等可以被檢測(cè)到,如果我們編譯就會(huì)出現(xiàn)編譯錯(cuò)誤。

如果要允許特定類型(例如,注冊(cè)自定義類型時(shí)),請(qǐng)將MessagePackAnalyzer.json放在項(xiàng)目根目錄下,并將生成操作設(shè)置為AdditionalFiles(其他文件)。

這是MessagePackAnalyzer.json內(nèi)容的一個(gè)示例。

[ "MyNamespace.FooClass", "MyNameSpace.BarStruct" ]

內(nèi)置的支持類型

這些類型可以默認(rèn)序列化。

基元(int、string等等), Enum, Nullable<>, TimeSpan, DateTime, DateTimeOffset, Nil, Guid, Uri, Version, StringBuilder, BitArray, ArraySegment<>, BigInteger, Complext, Task, Array[], Array[,], Array[,,], Array[,,,], KeyValuePair<,>, Tuple<,...>, ValueTuple<,...>, List<>, LinkedList<>, Queue<>, Stack<>, HashSet<>, ReadOnlyCollection<>, IList<>, ICollection<>, IEnumerable<>, Dictionary<,>, IDictionary<,>, SortedDictionary<,>, SortedList<,>, ILookup<,>, IGrouping<,>, ObservableCollection<>, ReadOnlyOnservableCollection<>, IReadOnlyList<>, IReadOnlyCollection<>, ISet<>, ConcurrentBag<>, ConcurrentQueue<>, ConcurrentStack<>, ReadOnlyDictionary<,>, IReadOnlyDictionary<,>, ConcurrentDictionary<,>, Lazy<>, Task<>, 自定義繼承ICollection <>或IDictionary <,>具有無參構(gòu)造方法, IList,IDictionary和自定義繼承ICollection或IDictionary具有無參構(gòu)造函數(shù)(包括ArrayList和Hashtable)。

您可以添加自定義類型的支持和一些官方/第三方擴(kuò)展包。 對(duì)于ImmutableCollections(ImmutableList <>等),對(duì)于ReactiveProperty和Unity(Vector3, Quaternion等等),對(duì)于F#(Record,FsList,Discriminated Unions等)。

MessagePack.Nil是MessagePack for C#的內(nèi)置null/void/unit表示類型。

對(duì)象序列化

MessagePack for C#可以序列化public Class或Struct,序列化目標(biāo)必須標(biāo)記[MessagePackObject]和[Key], Key類型可以選擇int或字符串。如果Key類型是int,則使用序列化格式為數(shù)組,如果Key類型是字符串,則使用序列化格式為鍵值對(duì),如果您定義了[MessagePackObject(keyAsPropertyName:true)],則不需要Key特性。

[MessagePackObject]
public class Sample1{[Key(0)] ?
?public int Foo { get; set; }[Key(1)] ?
??public int Bar { get; set; } }[MessagePackObject]
public class Sample2{[Key("foo")] ?
?public int Foo { get; set; }[Key("bar")] ?
? ?public int Bar { get; set; } }[MessagePackObject(keyAsPropertyName: true)]
? ?public class Sample3{ ? ?// 不需要key特性public int Foo { get; set; } ? ?// 不需要序列化的成員使用IgnoreMember特性[IgnoreMember] ?
? ??public int Bar { get; set; } }// 結(jié)果 [10,20]Console.WriteLine(MessagePackSerializer.ToJson(new Sample1 { Foo = 10, Bar = 20 }));// 結(jié)果 {"foo":10,"bar":20}
Console.WriteLine(MessagePackSerializer.ToJson(new Sample2 { Foo = 10, Bar = 20 }));// 結(jié)果 {"Foo":10}
Console.WriteLine(MessagePackSerializer.ToJson(new Sample3 { Foo = 10, Bar = 20 }));

所有模式序列化目標(biāo)都是公共實(shí)例成員(字段或?qū)傩?#xff09;。 如果要避免序列化目標(biāo),可以將[IgnoreMember]添加到目標(biāo)成員。

目標(biāo)類必須是 public, 不允許 private, internal 類.

應(yīng)該使用哪種Key類型,int或string? 作者建議使用int key,因?yàn)楸萻tring key更快,更緊湊。 但是string key有關(guān)鍵的名字信息,對(duì)調(diào)試很有用。

MessagePackSerializer序列化目標(biāo)時(shí),必須在目標(biāo)使用特性才能保證穩(wěn)健性,如果類進(jìn)行了擴(kuò)充,你必須意識(shí)到版本控制。如果Key不存在,MessagePackSerializer將會(huì)使用默認(rèn)值。如果使用的是int key,那么必須從0開始,如果不必要的屬性出現(xiàn),請(qǐng)?zhí)顚懣杖钡臄?shù)字。重用是不好的。 此外,如果Int Key的跳轉(zhuǎn)數(shù)字差距太大,則會(huì)影響二進(jìn)制大小。

[MessagePackObject]
public class IntKeySample{[Key(3)] ? ?
public int A { get; set; }[Key(10)] ? ?
public int B { get; set; } }// int key不從0開始并且數(shù)字進(jìn)行了跳躍,將會(huì)出現(xiàn)下面的結(jié)果//[null,null,null,0,null,null,null,null,null,null,0]
Console.WriteLine(MessagePackSerializer.ToJson(new IntKeySample()));

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

public class ContractlessSample{ ?
?public int MyProperty1 { get; set; } ? ?
?public int MyProperty2 { get; set; } }var data = new ContractlessSample { MyProperty1 = 99, MyProperty2 = 9999 };var bin = MessagePackSerializer.Serialize(data, MessagePack.Resolvers.ContractlessStandardResolver.Instance);// {"MyProperty1":99,"MyProperty2":9999}

Console.WriteLine(MessagePackSerializer.ToJson(bin));// 全局設(shè)置無約束解析器為默認(rèn)解析器MessagePackSerializer.SetDefaultResolver(MessagePack.Resolvers.ContractlessStandardResolver.Instance);// 序列化
var bin2 = MessagePackSerializer.Serialize(data);

我想序列化私人成員! 默認(rèn)情況下,不能序列化/反序列化私有成員。 但是你可以使用allow-private解析器來序列化私人成員。

[MessagePackObject]public class PrivateSample{[Key(0)] ? ?int x; ? ?public void SetX(int v) ? ?{x = v;} ? ?public int GetX() ? ?{ ? ? ? ?return x;} }var data = new PrivateSample(); data.SetX(9999);// 你可以選擇 StandardResolverAllowPrivate 或者 ?ContractlessStandardResolverAllowPrivate 解析器var bin = MessagePackSerializer.Serialize(data, MessagePack.Resolvers.DynamicObjectResolverAllowPrivate.Instance);

我不需要類型,我想像BinaryFormatter那樣使用! 你可以使用無類型的解析器和幫助器。 請(qǐng)參閱Typeless部分。

解析器是MessagePack For C#的關(guān)鍵定制點(diǎn)。 詳情請(qǐng)見擴(kuò)展部分。

DataContract兼容性

您可以使用[DataContract]而不是[MessagePackObject]。 如果type標(biāo)記為DataContract,則可以使用[DataMember]代替[Key],[IgnoreDataMember]代替[IgnoreMember]。

[DataMember(Order = int)] 和 [Key(int)]相同, [DataMember(Name = string)]和 [Key(string)]相同. 如果使用 [DataMember], 則類似于 [Key(nameof(propertyname)].

使用DataContract使其成為一個(gè)共享的類庫,您不必引用MessagePack for C#。 但是,它不包含在分析器或由mpc.exe生成的代碼中。此外,像UnionAttribute,MessagePackFormatterAttribute,SerializationConstructorAttribute等功能不能使用。 出于這個(gè)原因,我建議您基本上使用MessagePack for C#特性。

序列化不可變對(duì)象(序列化構(gòu)造器)

MessagePack for C#支持反序列化不可變對(duì)象。 例如,這個(gè)struct可以自然地序列化/反序列化。

[MessagePackObject]public struct Point {[Key(0)] ? ?public readonly int X;[Key(1)] ? ?public readonly int Y; ? ?public Point(int x, int y) ? ?{ ? ? ? ?this.X = x; ? ? ? ?this.Y = y;} }var data = new Point(99, 9999);var bin = MessagePackSerializer.Serialize(data);// Okay to deserialize immutable obejctvar point = MessagePackSerializer.Deserialize<Point>(bin);

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選擇具有最少參數(shù)的構(gòu)造方法,如果key是整型將匹配索引或者如果key是字符串將匹配名稱(忽略大小寫)。 如果遇到?MessagePackDynamicObjectResolverException: can't find matched constructor parameter?你應(yīng)該檢查一會(huì)下。

如果不能自動(dòng)匹配,可以通過[SerializationConstructorAttribute]手動(dòng)指定使用構(gòu)造函數(shù)。

[MessagePackObject]
public struct Point {[Key(0)] ?
?public readonly int X;[Key(1)] ?
??public readonly int Y; ? ?// 如果沒有標(biāo)記特性,將會(huì)使用這方法(最少參數(shù))public Point(int x) ? ?{X = x;}[SerializationConstructor] ?
?public Point(int x, int y) ? ?{ ? ?
? ? ?this.X = x; ? ? ?
? ? ??this.Y = y;} }

序列化回調(diào)

如果對(duì)象實(shí)現(xiàn)了IMessagePackSerializationCallbackReceiver,則接受OnBeforeSerialize和OnAfterDeserialize序列化處理。

[MessagePackObject]
public class SampleCallback : IMessagePackSerializationCallbackReceiver{[Key(0)] ?
?public int Key { get; set; } ?
? ?public void OnBeforeSerialize() ? ?{Console.WriteLine("OnBefore");} ?
? ?
? ?public void OnAfterDeserialize() ? ?{Console.WriteLine("OnAfter");} }

Union

MessagePack for C#支持序列化接口。這就像XmlInclude或ProtoInclude。在MessagePack for C#里叫Union。UnionAttribute只能附加到接口或抽象類。 它需要區(qū)分的整型key和子類型

// mark inheritance types[MessagePack.Union(0, typeof(FooClass))] [MessagePack.Union(1, typeof(BarClass))]
public interface IUnionSample{ }[MessagePackObject]
public class FooClass : IUnionSample{[Key(0)] ?
?public int XYZ { get; set; } }[MessagePackObject]
?public class BarClass : IUnionSample{[Key(0)] ? ?
?public string OPQ { get; set; } }// ---IUnionSample data = new FooClass() { XYZ = 999 };// serialize interface.

var bin = MessagePackSerializer.Serialize(data);// deserialize interface.

var reData = MessagePackSerializer.Deserialize<IUnionSample>(bin);// use type-switch of C# 7.0

switch (reData) { ? ?case FooClass x:Console.WriteLine(x.XYZ); ? ? ?
? ?break; ? ?
? ?case BarClass x:Console.WriteLine(x.OPQ); ? ? ?
? ??break;
? ??? ?default: ? ?
? ??? ? ? ?break; }

C#7.0 type-switch是Union的最佳選擇。 Union被序列化為兩個(gè)長(zhǎng)度的數(shù)組。

IUnionSample data = new BarClass { OPQ = "FooBar" };
var bin = MessagePackSerializer.Serialize(data);// Union is serialized to two-length array, [key, object]// [1,["FooBar"]]
Console.WriteLine(MessagePackSerializer.ToJson(bin));

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

[Union(0, typeof(SubUnionType1))] [Union(1, typeof(SubUnionType2))] [MessagePackObject]
public abstract class ParentUnionType{[Key(0)] ? ?
public int MyProperty { get; set; } }[MessagePackObject]
public class SubUnionType1 : ParentUnionType{[Key(1)] ?
?public int MyProperty1 { get; set; } }[MessagePackObject]
?public class SubUnionType2 : ParentUnionType{[Key(1)] ? ?
? ? ?public int MyProperty2 { get; set; } }

繼承類型的序列化,在數(shù)組(或鍵值對(duì))中是扁平化的,對(duì)于整型鍵是無關(guān)緊要的,它不能復(fù)制父類和所有的子類。

Dynamic(Untyped)反序列化

如果使用MessagePackSerializer.Deserialize<object>?或者M(jìn)essagePackSerializer.Deserialize<dynamic>,messagepack將轉(zhuǎn)換為 primitive values,msgpack-primitive將轉(zhuǎn)換為bool, char, sbyte, byte, short, int, long, ushort, uint, ulong, float, double, DateTime, string, byte[], object[], IDictionary<object, object>.

// sample binary.
var model = new DynamicModel { Name = "foobar", Items = new[] { 1, 10, 100, 1000 } };
var bin = MessagePackSerializer.Serialize(model, ContractlessStandardResolver.Instance);// dynamic, untyped
var dynamicModel = MessagePackSerializer.Deserialize<dynamic>(bin, ContractlessStandardResolver.Instance);Console.WriteLine(dynamicModel["Name"]); // foobarConsole.WriteLine(dynamicModel["Items"][2]); // 100

所以你可以使用索引訪問鍵值對(duì)或者數(shù)組。

Object 類型序列化

StandardResolver和ContractlessStandardResolver可以通過DynamicObjectTypeFallbackResolver將Object類型序列化為具體類型。

var objects = new object[] { 1, "aaa", new ObjectFieldType { Anything = 9999 } };
var bin = MessagePackSerializer.Serialize(objects);// [1,"aaa",[9999]]
Console.WriteLine(MessagePackSerializer.ToJson(bin));// Support Anonymous Type Serialize
var anonType = new { Foo = 100, Bar = "foobar" };
var bin2 = MessagePackSerializer.Serialize(anonType, MessagePack.Resolvers.ContractlessStandardResolver.Instance);// {"Foo":100,"Bar":"foobar"}
Console.WriteLine(MessagePackSerializer.ToJson(bin2));

Unity支持是有限的。

反序列化時(shí),與Dynamic(Untyped)反序列化相同。

Typeless

Typeless API就像BinaryFormatter, 將類型信息嵌入到二進(jìn)制中,所以不需要類型去反序列化.

object mc = new Sandbox.MyClass() {Age = 10,FirstName = "hoge",LastName = "huga"};// serialize to typelessvar bin = MessagePackSerializer.Typeless.Serialize(mc);// binary data is embeded type-assembly information.// ["Sandbox.MyClass, Sandbox",10,"hoge","huga"]
Console.WriteLine(MessagePackSerializer.ToJson(bin));// can deserialize to MyClass with typeless
var objModel = MessagePackSerializer.Typeless.Deserialize(bin) as MyClass;

類型信息由mspgack ext格式序列化,typecode為100。

MessagePackSerializer.Typeless是Serialize / Deserialize <object>(TypelessContractlessStandardResolver.Instance)的快捷方式。 如果要配置默認(rèn)的Typeless解析器,可以通過MessagePackSerializer.Typeless.RegisterDefaultResolver進(jìn)行設(shè)置。

性能

與其他序列化器在Windows 10 Pro x64 Intel Core i7-6700K 4.00GHz, 32GB RAM上進(jìn)行Benchmarks比較,Benchmark代碼在這-版本信息,ZeroFormatter和FlatBuffers具有非常快速的反序列化器,因此忽略反序列化的性能。

MessagePack for C#使用許多技術(shù)來提高性能。

  • 序列化只使用ref byte []和int offset,不使用(Memory)Stream(調(diào)用Stream api會(huì)有開銷)

  • 高級(jí)API使用內(nèi)部?jī)?nèi)存池,分配工作內(nèi)存不要低于64k

  • 不創(chuàng)建中間實(shí)用程序?qū)嵗?#xff08;XxxWriter / Reader,XxxContext等)

  • 所有代碼避免裝箱,所有平臺(tái)(包括Unity / IL2CPP)

  • 對(duì)靜態(tài)泛型字段生成的格式化程序進(jìn)行緩存,查找時(shí)從緩存查找(不使用字典緩存,因?yàn)樽值洳檎倚枰欢ㄩ_銷)

  • 重新調(diào)整的動(dòng)態(tài)代碼生成

  • 當(dāng)代碼生成知道目標(biāo)是primitive時(shí)直接調(diào)用PrimitiveAPI

  • 當(dāng)代碼生成知道目標(biāo)(整數(shù)/字符串)范圍時(shí),減少可變長(zhǎng)度格式的分支

  • 不在迭代集合上使用IEnumerable<T> 抽象

  • 使用預(yù)先生成的查找表來減少檢查消息包類型所耗時(shí)間

  • 對(duì)非泛型方法使用優(yōu)化類型key字典

  • 避免查找映射(字符串鍵)鍵的字符串鍵解碼,并使用自動(dòng)化名稱查找與il內(nèi)聯(lián)代碼生成

  • 對(duì)于字符串鍵編碼,預(yù)先生成的成員名字節(jié)并在IL中使用固定大小的二進(jìn)制副本

在創(chuàng)建這個(gè)庫之前,作則實(shí)現(xiàn)了一個(gè)具有ZeroFormatter#Performance的快速序列化器。 這是一個(gè)進(jìn)一步演變的實(shí)現(xiàn)。 MessagePack for C#始終是快速的,為所有類型(原始,小結(jié)構(gòu),大對(duì)象,任何集合)進(jìn)行了優(yōu)化。

反序列化中每個(gè)方法的性能

性能取決于選項(xiàng)。 這是一個(gè)BenchmarkDotNet的微型benchamark。 目標(biāo)對(duì)象有9個(gè)成員(MyProperty1?MyProperty9),值為零。

MethodMeanErrorScaledGen 0Allocated
IntKey72.67 nsNA1.000.013256 B
StringKey217.95 nsNA3.000.013156 B
Typeless_IntKey176.71 nsNA2.430.013156 B
Typeless_StringKey378.64 nsNA5.210.012956 B
MsgPackCliMap1,355.26 nsNA18.650.1431608 B
MsgPackCliArray455.28 nsNA6.260.0415176 B
ProtobufNet265.85 nsNA3.660.0319136 B
Hyperion366.47 nsNA5.040.0949400 B
JsonNetString2,783.39 nsNA38.300.67902864 B
JsonNetStreamReader3,297.90 nsNA45.381.42676000 B
JilString553.65 nsNA7.620.0362152 B
JilStreamReader1,408.46 nsNA19.380.84503552 B

IntKey,StringKey,Typeless_IntKey,Typeless_StringKey都是MessagePack for C#的方法
,在反序列化過程中實(shí)現(xiàn)零內(nèi)存分配。JsonNetString /JilString從字符串反序列化。JsonStStreamReader / JilStreamReader是從StreamReader的UTF8 byte []中反序列化的。反序列化通常從Stream讀取。 因此,它將從字節(jié)數(shù)組(或流)而不是字符串中讀取。

MessagePack for C#IntKey是最快的。 StringKey比IntKey慢,因?yàn)镾tringKey需要從字符串進(jìn)行匹配。 如果是IntKey,讀取數(shù)組長(zhǎng)度,根據(jù)數(shù)組長(zhǎng)度進(jìn)行for循環(huán)二進(jìn)制解碼。 如果StringKey,讀取map 長(zhǎng)度,根據(jù)map長(zhǎng)度循環(huán),首先需要對(duì)密鑰解碼,然后按照key查找,最后二進(jìn)制解碼,則需要額外兩個(gè)步驟(解碼密鑰和按鍵查找)。

字符串鍵通常是有用的,無約束的,簡(jiǎn)單的JSON替換,與其他語言的互操作性,以及更多的某些版本。 MessagePack for C#也為String Key進(jìn)行了優(yōu)化。 首先,它不會(huì)將UTF8字節(jié)數(shù)組解碼為與成員名稱匹配的字符串,它會(huì)按原樣查找字節(jié)數(shù)組(避免解碼成本和額外分配)。

它會(huì)嘗試匹配每個(gè)長(zhǎng)整型(long)(每8個(gè)字符,如果長(zhǎng)度不夠,填充0)使用automata和在生成時(shí)內(nèi)聯(lián)IL代碼。

這也避免了計(jì)算字節(jié)數(shù)組的哈希碼,并且可以在長(zhǎng)單元上進(jìn)行多次比較。

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

https://github.com/neuecc/MessagePack-CSharp#performance

如果節(jié)點(diǎn)數(shù)量很大,則使用嵌入式二進(jìn)制搜索進(jìn)行搜索。

另外請(qǐng)注意,這是序列化的基準(zhǔn)測(cè)試結(jié)果。

MethodMeanErrorScaledGen 0Allocated
IntKey84.11 nsNA1.000.009440 B
StringKey126.75 nsNA1.510.0341144 B
Typeless_IntKey183.31 nsNA2.180.0265112 B
Typeless_StringKey193.95 nsNA2.310.0513216 B
MsgPackCliMap967.68 nsNA11.510.1297552 B
MsgPackCliArray284.20 nsNA3.380.1006424 B
ProtobufNet176.43 nsNA2.100.0665280 B
Hyperion280.14 nsNA3.330.1674704 B
ZeroFormatter149.95 nsNA1.780.1009424 B
JsonNetString1,432.55 nsNA17.030.46161944 B
JsonNetStreamWriter1,775.72 nsNA21.111.55266522 B
JilString547.51 nsNA6.510.34811464 B
JilStreamWriter778.78 nsNA9.261.44486066 B

當(dāng)然,IntKey是最快的,但StringKey也不錯(cuò)。

LZ4壓縮

MessagePack是一個(gè)快速和緊湊的格式,但它不是壓縮格式。 LZ4是非常快速的壓縮算法,使用MessagePack for C#可以實(shí)現(xiàn)極快的性能和非常緊湊的二進(jìn)制大小!

MessagePack for C#具有內(nèi)置的LZ4支持。 您可以使用LZ4MessagePackSerializer而不是MessagePackSerializer。 內(nèi)建支持是特殊的,作者已經(jīng)創(chuàng)建了序列化壓縮管道,并專門調(diào)整了管道,所以共享工作內(nèi)存,不分配,不要調(diào)整,直到完成。

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

var array= Enumerable.Range(1, 100).Select(x => new MyClass { Age = 5, FirstName = "foo", LastName = "bar" }).ToArray();// call LZ4MessagePackSerializer instead of MessagePackSerializer, api is completely samevar lz4Bytes = LZ4MessagePackSerializer.Serialize(array);var mc2 = LZ4MessagePackSerializer.Deserialize<MyClass[]>(lz4Bytes);// you can dump lz4 message pack// [[5,"hoge","huga"],[5,"hoge","huga"],....]var json = LZ4MessagePackSerializer.ToJson(lz4Bytes); Console.WriteLine(json);// lz4Bytes is valid MessagePack, it is using ext-format( [TypeCode:99, SourceLength|CompressedBinary] )// [99,"0gAAA+vf3ABkkwWjZm9vo2JhcgoAyVBvo2Jhcg=="]var rawJson = MessagePackSerializer.ToJson(lz4Bytes); Console.WriteLine(rawJson);

與protobuf,JSON,ZeroFormatter比較

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

[ProtoContract]public class Parent{[ProtoMember(1)] ? ?public int Primitive { get; set; }[ProtoMember(2)] ? ?public Child Prop { get; set; }[ProtoMember(3)] ? ?public int[] Array { get; set; } }[ProtoContract]public class Child{[ProtoMember(1)] ? ?public int Number { get; set; } }using (var ms = new MemoryStream()) { ? ?// serialize null.ProtoBuf.Serializer.Serialize<Parent>(ms, null);ms.Position = 0; ? ?var result = ProtoBuf.Serializer.Deserialize<Parent>(ms);Console.WriteLine(result != null); // True, not null. but all property are zero formatted.Console.WriteLine(result.Primitive); // 0Console.WriteLine(result.Prop); // nullConsole.WriteLine(result.Array); // null}using (var ms = new MemoryStream()) { ? ?// serialize empty array.ProtoBuf.Serializer.Serialize<Parent>(ms, new Parent { Array = new int[0] });ms.Position = 0; ? ?var result = ProtoBuf.Serializer.Deserialize<Parent>(ms);Console.WriteLine(result.Array == null); // True, null!}

protobuf(-net)不能正確處理null和空集合。 因?yàn)閜rotobuf沒有null表示(這是protobuf-net作者的答案)。

MessagePack規(guī)范可以完全序列化C#類型。 這就是推薦MessagePack而不是protobuf的原因。

Protocol Buffers具有良好的IDL和gRPC,這比MessagePack好得多。 如果你想使用IDL,我(作者)推薦Google.Protobuf。

JSON是很好的通用格式。 這是完美的,簡(jiǎn)單的,足夠規(guī)范的。 Utf8Json創(chuàng)建了我采用與MessagePack for C#相同的體系結(jié)構(gòu),并避免編碼/修飾成本,所以像二進(jìn)制一樣工作。 如果你想了解二進(jìn)制與文本,請(qǐng)參閱Utf8Json /應(yīng)使用哪個(gè)序列化器部分。

ZeroFormatter與FlatBuffers類似,但專門用于C#。 這是特別的。 反序列化速度非常快,但是二進(jìn)制大小卻很大。 而ZeroFormatter的緩存算法需要額外的內(nèi)存。

ZeroFormatter也是特別的。 當(dāng)與ZeroFormatter對(duì)比的情況下,它顯示格式化的力量。 但是對(duì)于許多常見的用途,MessagePack for C#會(huì)更好。

擴(kuò)展

MessagePack for C#具有擴(kuò)展點(diǎn),您可以添加外部類型的序列化支持。 下列是官方擴(kuò)展支持。

Install-Package MessagePack.ImmutableCollectionInstall-Package MessagePack.ReactivePropertyInstall-Package MessagePack.UnityShimsInstall-Package MessagePack.AspNetCoreMvcFormatter

MessagePack.ImmutableCollection添加對(duì)?System.Collections.Immutable的支持. 添加了對(duì)ImmutableArray<>, ImmutableList<>, ImmutableDictionary<,>, ImmutableHashSet<>, ImmutableSortedDictionary<,>, ImmutableSortedSet<>, ImmutableQueue<>, ImmutableStack<>, IImmutableList<>, IImmutableDictionary<,>, IImmutableQueue<>, IImmutableSet<>, IImmutableStack<>的序列化支持.

MessagePack.ReactiveProperty包添加對(duì)ReactiveProperty庫的支持。它增加了ReactiveProperty <>,IReactiveProperty <>,IReadOnlyReactiveProperty <>,ReactiveCollection <>,unit序列化支持。 這對(duì)保存視圖模型狀態(tài)很有用。

MessagePack.AspNetCoreMvcFormatter是ASP.NET Core MVC序列化的附加組件,可提升性能。 這是配置示例。

public void ConfigureServices(IServiceCollection services){services.AddMvc().AddMvcOptions(option =>{option.OutputFormatters.Clear();option.OutputFormatters.Add(new MessagePackOutputFormatter(ContractlessStandardResolver.Instance));option.InputFormatters.Clear();option.InputFormatters.Add(new MessagePackInputFormatter(ContractlessStandardResolver.Instance));}); }

更多信息請(qǐng)?jiān)L問github:?https://github.com/neuecc/MessagePack-CSharp

原文地址:http://www.cnblogs.com/stulzq/p/8039933.html


.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com

總結(jié)

以上是生活随笔為你收集整理的快速序列化组件MessagePack介绍的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。