8

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

在使用 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;
    }
}
4

1 回答 1

6

protobuf-net 永远不会调用您的Clear()方法本身,但对于简单的情况,您可以自己简单地执行此操作,并使用该Merge方法(在 v1 API 上,或者只是将对象传递到Deserializev2 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- 如果工厂方法未在相关类型中声明,则很有用)

With this, what should happen is the factory method is used instead of the usual construction mechanisms. It remains, however, entirely your job to cleanse (Clear()) the objects when you are finished with them, and to return them to your pool. What is particularly nice about the factory approach is that it will work for new sub-items in lists, etc, which you can't do just from Merge.

于 2012-08-15T09:30:22.227 回答