c# - Google Protocol Buffers 序列化挂起写入 1GB+ 数据

标签 c# .net serialization protocol-buffers protobuf-net

我正在使用 Protocol Buffer 序列化对大型数据集进行序列化。当我的数据集包含 400000 个组合大小约为 1 GB 的自定义对象时,序列化将在 3~4 秒内返回。但是当我的数据集包含 450000 个组合大小约为 1.2 GB 的对象时,序列化调用永远不会返回并且 CPU 会不断消耗。

我正在使用 Protocol Buffers 的 .NET 端口。

最佳答案

查看新评论,这似乎(如 OP 所述)MemoryStream 容量受限。 protobuf 规范中的一个小问题是,由于子消息的长度是可变的,并且必须前缀 子消息,因此通常需要缓冲部分直到知道长度。这对于大多数合理的图来说很好,但是如果有一个特别大的图(除了“根对象有数百万个直接子对象”的情况,它不会受到影响)它最终可能会在内存中做很多事情。

如果您不受特定布局的约束(可能是由于 .proto 与现有客户端的互操作),那么一个简单的修复如下:在 child (子对象)属性上(包括列表/子对象数组),告诉它使用“组”序列化。这不是默认布局,不是,但它表示“不使用长度前缀,而是使用开始/结束标记对”。这样做的缺点是如果您的反序列化代码不知道某个特定对象,则跳过该字段需要更长的时间,因为它不能只说“寻求转发 231413 字节” - 它必须遍历 token 才能知道对象何时完成。在大多数情况下,这根本不是问题,因为您的反序列化代码完全需要该数据。

为此:

[ProtoMember(1, DataFormat = DataFormat.Group)]
public SomeType SomeChild { get; set; }
....
[ProtoMember(4, DataFormat = DataFormat.Group)]
public List<SomeOtherType> SomeChildren { get { return someChildren; } }

protobuf-net 中的反序列化非常宽容(默认情况下有一个可选的严格模式),它会愉快地反序列化组代替长度前缀,长度前缀代替组(意思是:你的任何数据已经存储在某个地方应该可以正常工作)。

关于c# - Google Protocol Buffers 序列化挂起写入 1GB+ 数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6357645/

相关文章:

c# - ASP.NET 上 C# 中的当前请求全局变量

c# - 在 c# 中替代 switch 语句调用方法

.net - 同时调用 StorageFolder.GetFolderFromPathAsync 时出现 ArgumentException

c# - C# 中的方法可以覆盖另一个方法并同时是虚拟的吗?

c# - DbSet.Cast<TEntity>() 错误 : Cannot create a DbSet<IEntity> from a non-generic DbSet for objects of type 'Entity'

c++ - 在 Visual Studio 中编译 CLD2

c# - 如何在 C# 中触摸文件?

ruby - 用 Ruby 编写 YAML 文件 : lack of pretty printing formatting options

java - JSON 反序列化抛出异常 - 无法从 START_OBJECT token 中反序列化 java.util.ArrayList 的实例

c# - 反序列化复杂类型但保持选定属性为序列化状态