我可以重用对象实例来避免使用protobuf-net进行分配吗?

时间:2012-08-15 09:30:22

标签: c# .net protobuf-net

上下文:这是基于在我回答之前被问及然后删除的问题 - 但我认为这是一个很好的问题,所以我整理了它,改写它,并重新发布它

在使用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 个答案:

答案 0 :(得分:6)

protobuf-net永远不会调用你的Clear()方法本身,但对于简单的情况,你可以自己做,并使用Merge方法(在v1 API上,或者只是将对象传递给v2 API中的Deserialize。例如:

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开始。