我有一个缓存服务,它包含多个Price对象,这些对象会在新价格增量到达时更新,有时会每秒多次。 每个对象在分配给ID的集合中保存它的各种价格。如果有人订阅特定价格,我需要在每次新价格到达时将最新价格对象序列化为JSON,以便通过RMQ发送。我遇到的问题是,在某些情况下,我在序列化时收到以下错误消息,因为新的价格已经到达并在上一个序列化期间更新了对象上的集合。
“收集已修改;枚举操作可能无法执行。”
我尝试了各种序列化对象的方法(它需要尽可能快)但我仍然遇到同样的问题。
解决此问题的最佳和最有效方法是什么,即使对象发生变化,我也可以序列化。
简化的对象是:
//This is the collection on an object that holds the prices which are being updated
public ConcurrentDictionary<Id, Prices> Asset{ get; set; }
//Class that holds the ever updating prices
[Serializable]
public class Prices
{
public Prices()
{
Prices1 = new List<PriceVolume>();
Prices2 = new List<PriceVolume>();
}
}
提前感谢!
答案 0 :(得分:0)
您应该创建一个深层副本并序列化副本,而不是序列化从并发字典中提取的实际对象。不幸的是,您仍然需要将代码放入互斥锁中。 ConcurrentDic仅保护您在检索项目时不会更改或删除项目,它不会在您检索到对象的引用后保护对象不受操纵。
答案 1 :(得分:0)
在序列化时,您可能会从locking
元素中受益。
锁定时,锁定会阻止其他线程修改元素。
这将使操作尝试更改价格等待,直到您完成序列化以修改它们。
[Serializable]
public class Prices
{
public string Serialize()
{
lock (this)
{
// logic for serilization here
}
}
}
答案 2 :(得分:0)
只是一个想法,但是如何看待序列化回调(有些人将其称为序列化挂钩)和实现 ISerializable 接口。您似乎需要对对象的序列化进行更细粒度的控制。看看这个链接:
请看以下
另请看这个链接:
Version Tolerant Serialization
您可以考虑对象是否保证在某些字段上使用 OptionalFieldAttribute 或 NonSerializedAttribute 来控制是否需要序列化或可选地序列化。请注意使用 NonSerializedAttribute 。看看文章中提到的最佳实践(转载于此处以供参考):
要确保正确的版本控制行为,请在将类型从版本修改为版本时遵循以下规则:
永远不要删除序列化字段
如果该属性未应用于上一版本中的字段,请勿将 NonSerializedAttribute 属性应用于字段
永远不要更改序列化字段的名称或类型
- 添加新的序列化字段时,应用 OptionalFieldAttribute 属性
从字段中移除 NonSerializedAttribute 属性(在以前的版本中无法序列化)时,应用 OptionalFieldAttribute 属性
对于所有可选字段,使用序列化回调设置有意义的默认值,除非默认为0或null作为默认值
要确保类型与将来的序列化引擎兼容,请遵循以下准则:
- 始终在 OptionalFieldAttribute 属性上正确设置VersionAdded属性
- 避免分支版本化