上下文:这是基于在我回答之前被问及然后删除的问题 - 但我认为这是一个很好的问题,所以我整理了它,改写它,并重新发布它的
在使用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;
}
}
答案 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
开始。