如何对已知固定类型的小型结构体数组实现高效序列化?
方案1:原生二进制裸写 + 自定义轻量RLE压缩
因为你的Voxel结构体所有字段都是单字节byte类型,本身完全不存在字节序适配问题,哪怕直接内存拷贝读写都不会有跨平台字节序错误,比Marshal方案更简单:
- 序列化逻辑:
- 先写入4字节的数组长度标识(Int32,固定小端/大端即可,单值转换成本可忽略)
- 遍历数组做RLE编码:相同
density+material组合的连续Voxel,存为「(1字节标记位) + 2字节Voxel值 + 2字节连续长度」,非连续的零散Voxel直接存2字节原值即可,RLE编码后直接写入流
- 反序列化逻辑:
- 先读4字节拿到数组总长度,提前分配对应大小的数组,避免扩容开销
- 按RLE规则逐条解码写入数组即可
该方案性能天花板最高,100万条数据序列化/反序列化耗时基本在1ms以内,磁盘占用比裸存低30%~90%(取决于数据重复度)。
方案2:使用BinaryPrimitives + 内置Deflate压缩
如果不想自己写RLE编码,可以用.NET内置的类实现,稳定性更高:
- 序列化时直接将
Voxel[]转为Span<byte>(C# 7.2+支持,无需unsafe代码也可操作),直接用BinaryPrimitives写流,外层套DeflateStream做压缩 - 不需要处理字节序的核心原因还是你的结构体全是单字节字段,
Span<byte>直接映射内存的读写不会有字节序错误
该方案代码量极少,性能比自定义RLE略低10%左右,磁盘压缩率和RLE接近(数据重复度高时RLE更好,随机数据时Deflate更好)。
方案3:使用MessagePack-CSharp的无压缩模式
如果希望后续有小幅扩展空间,又不想损失性能,可以用MessagePack的固定结构序列化:
- 给
Voxel结构体加[MessagePackObject]特性,两个字段用[Key(0)]、[Key(1)]标记,开启ForceImmutable开关 - 序列化时直接传数组,不需要启用压缩,单条Voxel序列化后只占2字节,和裸存体积一致,序列化速度接近原生读写
该方案不需要自己处理编码逻辑,后续如果要加字段也可以兼容,性能比前两个方案低15%~20%,但远高于JSON、Protobuf等通用序列化方案。
补充注意:如果你的数据里连续重复的Voxel占比超过30%,优先选自定义RLE方案,磁盘占用能降到裸存的1/10甚至更低;如果数据随机性高,选Deflate压缩的方案更省事。
内容的提问来源于stack exchange,提问作者bitinn
相关产品推荐
相关产品推荐

