我可以重复使用对象实例来避免使用 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.Deserialize(Stream)。还有办法指定要填充的对象实例吗?我想重用对象池中的对象,这种方式似乎比使用自定义工厂的其他方式更容易处理......提前致谢。 @Eric v1 API (Serializer.*) 你想要的方法是Merge。在 v2 API (TypeModel) 上,Deserialize 过载。 非常感谢。我使用的是静态类 Serializer 而不是 TypeModel!

以上是关于我可以重复使用对象实例来避免使用 protobuf-net 进行分配吗?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 protobuf-net 与通过 ASP.NET Web Reference 生成的类一起使用,同时避免代码重复?

游戏开发笔记:protobuf避免重复代码newBuilder

Django/Python DRY:使用 Q 对象和模型属性时如何避免重复代码

如何避免将重复对象加载到主内存中?

ProtoBuf WCF“未分配模型实例”

rust下根据protobuf的消息名创建对象实例