使用起来应该是这几个二进制序列化协议最简单的了 , 只需要给对应的类加上partial
关键字,另外打上MemoryPackable
特性即可:
[MemoryPackable]public partial class DemoClass{public int P1 { get; set; }public bool P2 { get; set; }public string P3 { get; set; } = null!;public double P4 { get; set; }public long P5 { get; set; }}
序列化和反序列化也是调用静态方法:
// Serialize[MethodImpl(MethodImplOptions.AggressiveInlining)]public static byte[] MemoryPack<T>(T origin){return global::MemoryPack.MemoryPackSerializer.Serialize(origin);}// Deserializepublic T MemoryPack<T>(byte[] bytes){return global::MemoryPack.MemoryPackSerializer.Deserialize<T>(bytes)!;}
它原生支持Brotli压缩算法,使用如下所示:
// Serialize[MethodImpl(MethodImplOptions.AggressiveInlining)]public static byte[] MemoryPackBrotli<T>(T origin){using var compressor = new BrotliCompressor();global::MemoryPack.MemoryPackSerializer.Serialize(compressor, origin);return compressor.ToArray();}// Deserializepublic T MemoryPackBrotli<T>(byte[] bytes){using var decompressor = new BrotliDecompressor();var decompressedBuffer = decompressor.Decompress(bytes);return MemoryPackSerializer.Deserialize<T>(decompressedBuffer)!;}
跑个分吧我使用BenchmarkDotNet
构建了一个10万个对象序列化和反序列化的测试,源码在末尾的Github链接可见,比较了序列化、反序列化的性能,还有序列化以后占用的空间大小 。
public static class TestData{//public static readonly DemoClass[] Origin = Enumerable.Range(0, 10000).Select(i =>{return new DemoClass{P1 = i,P2 = i % 2 == 0,P3 = $"Hello World {i}",P4 = i,P5 = i,Subs = new DemoSubClass[]{new() {P1 = i, P2 = i % 2 == 0, P3 = $"Hello World {i}", P4 = i, P5 = i,},new() {P1 = i, P2 = i % 2 == 0, P3 = $"Hello World {i}", P4 = i, P5 = i,},new() {P1 = i, P2 = i % 2 == 0, P3 = $"Hello World {i}", P4 = i, P5 = i,},new() {P1 = i, P2 = i % 2 == 0, P3 = $"Hello World {i}", P4 = i, P5 = i,},}};}).ToArray();public static readonly DemoClassProto.DemoClassArrayProto OriginProto;static TestData(){OriginProto = new DemoClassArrayProto();for (int i = 0; i < Origin.Length; i++){OriginProto.DemoClass.Add(DemoClassProto.DemoClassProto.Parser.ParseJson(JsonSerializer.Serialize(Origin[i])));}}}
序列化序列化的Bemchmark的结果如下所示:
文章插图
从序列化速度来看
MemoryPack
遥遥领先 , 比JSON要快88%,甚至比Protobuf快15% 。文章插图
从序列化占用的内存来看,
MemoryPackBrotli
是王者,它比JSON占用少98% , 甚至比Protobuf
占用少25% 。其中ProtoBufDotNet
内存占用大主要还是吃了没有byte[]
返回方法的亏,只能先创建一个MemoryStream
。文章插图
序列化结果大小这里我们可以看到
MemoryPackBrotli
赢麻了,比不压缩的MemoryPack
和Protobuf
有着10多倍的差异 。文章插图
反序列化反序列化的Benchmark结果如下所示,反序列化整体开销是比序列化大的,毕竟需要创建大量的对象:
文章插图
从反序列化的速度来看,不出意外
MemoryPack
还是遥遥领先,比JSON快80% , 比Protobuf
快14% 。文章插图
从内存占用来看
ProtobufDotNet
是最小的,这个结果听让人意外的,其余的都表现的差不多:文章插图
总结总的相关数据如下表所示 , 原始数据可以在文末的Github项目地址获?。?
文章插图
从图表来看,如果要兼顾序列化后大小和性能的话我们应该要选择
MemoryPackBrotli
,它序列化以后的结果最?。?而且兼顾了性能:文章插图
不过由于
MemoryPack
目前需要.NET7版本,所以现阶段最稳妥的选择还是使用MessagePack
+Lz4
压缩算法,它有着不俗的性能表现和突出的序列化大小 。回到文首的技术选型问题,笔者那个项目最终选用的是
推荐阅读
- 华为云 MRS 基于 Apache Hudi 极致查询优化的探索实践
- 基于 .NET 7 的 QUIC 实现 Echo 服务
- 《ASP.NET Core技术内幕与项目实战》精简集-目录
- 上 学习ASP.NET Core Blazor编程系列十——路由
- 重新整理 .net core 实践篇 ———— linux上性能排查 [外篇]
- Sql Server性能排查和优化懒人攻略
- 在 .NET 7上使用 WASM 和 WASI
- 重新整理 .net core 实践篇 ———— linux上排查问题实用工具 [外篇]
- .NET 7 中 LINQ 的疯狂性能提升
- Vue3的新特性