我可以重复使用对象实例来避免使用 protobuf-net 进行分配吗?
Posted
技术标签:
【中文标题】我可以重复使用对象实例来避免使用 protobuf-net 进行分配吗?【英文标题】:Can I re-use object instances to avoid allocations with protobuf-net? 【发布时间】:2012-08-15 09:30:22 【问题描述】:上下文:这是基于一个在我回答之前被问到然后删除的问题 - 但我认为这是一个很好的问题,所以我整理了它,重新措辞并重新发布了它.
在使用 protobuf-net 的高吞吐量场景中,大量分配是一个问题(特别是对于 GC),是否可以重用对象?例如通过添加Clear()
方法?
[ProtoContract]
public class MyDTO
[ProtoMember(1)]
public int Foo get; set;
[ProtoMember(2)]
public string Bar get; set;
[ProtoMember(3, DataFormat = DataFormat.Group)]
public List<int> Values get return values;
private readonly List<int> values = new List<int>();
public void Clear()
values.Clear();
Foo = 0;
Bar = null;
【问题讨论】:
【参考方案1】:protobuf-net 永远不会调用您的 Clear()
方法本身,但对于简单的情况,您可以简单地自己执行此操作,并使用 Merge
方法(在 v1 API 上,或者只是将对象传递到 Deserialize
中v2 API)。例如:
MyDTO obj = new MyDTO();
for(...)
obj.Clear();
Serializer.Merge(obj, source);
这会将数据加载到现有 obj
,而不是每次都创建一个新对象。
在更复杂的场景中,您希望减少对象分配的数量,并且乐于自己处理对象池/重用,那么您可以使用自定义工厂。比如可以给MyDTO
添加一个方法如:
// this can also accept serialization-context parameters if
// you want to pass your pool in, etc
public static MyDTO Create()
// try to get from the pool; only allocate new obj if necessary
return SomePool.GetMyDTO() ?? new MyDTO();
并且,在应用程序启动时,配置 protobuf-net 以了解它:
RuntimeTypeModel.Default[typeof(MyDTO)].SetFactory("Create");
(SetFactory
也可以接受 MethodInfo
- 如果工厂方法未在相关类型中声明,则很有用)
有了这个,应该发生的是使用工厂方法而不是通常的构造机制。但是,当您完成对象时,清理 (Clear()
) 对象并将它们返回到您的池中,这完全是您的工作。工厂方法特别好的地方在于它适用于列表等中的新子项,而您不能仅通过 Merge
做到这一点。
【讨论】:
嗨,Marc,如果我不实现 Clear() 方法会怎样?无论如何都会覆盖所有字段吗? @driAn 只会分配入站流中包含数据的字段。如果您使用回收实例的自定义工厂,您应该在工厂内提供您自己的重置代码。如果您不使用自定义工厂,这不是问题 嗨,Marc,我正在寻找上述方法 Deserialize() 以及要填充/合并的对象实例。但我没有找到。我只找到一种方法:Serializer.DeserializeSerializer.*
) 你想要的方法是Merge
。在 v2 API (TypeModel
) 上,Deserialize
过载。
非常感谢。我使用的是静态类 Serializer 而不是 TypeModel!以上是关于我可以重复使用对象实例来避免使用 protobuf-net 进行分配吗?的主要内容,如果未能解决你的问题,请参考以下文章
如何将 protobuf-net 与通过 ASP.NET Web Reference 生成的类一起使用,同时避免代码重复?
游戏开发笔记:protobuf避免重复代码newBuilder