Protobuf.netexception – 检查元数据时超时

尝试使用protobuf.net反序列化对象时, 有时会收到以下exception。 我很惊讶,因为我从来没有多个线程同时反序列化同一个对象,并且protobuf.net源似乎没有使用任何静态对象进行反序列化。 exception确实提出了一个解决方案,但我不确定如何实现,所以欢迎一个例子。

Base Exception Type: System.TimeoutException: Timeout while inspecting metadata; this may indicate a deadlock. This can often be avoided by preparing necessary serializers during application initialization, rather than allowing multiple threads to perform the initial metadata inspection at ProtoBuf.Meta.RuntimeTypeModel.TakeLock(Boolean& lockTaken) at ProtoBuf.Meta.RuntimeTypeModel.FindOrAddAuto(Type type, Boolean demand, Boolean addWithContractOnly, Boolean addEvenIfAutoDisabled) at ProtoBuf.Meta.RuntimeTypeModel.GetKey(Type type, Boolean demand, Boolean getBaseKey) Inner Exception Type: System.TimeoutException: Timeout while inspecting metadata; this may indicate a deadlock. This can often be avoided by preparing necessary serializers during application initialization, rather than allowing multiple threads to perform the initial metadata inspection at ProtoBuf.Meta.RuntimeTypeModel.TakeLock(Boolean& lockTaken) at ProtoBuf.Meta.RuntimeTypeModel.FindOrAddAuto(Type type, Boolean demand, Boolean addWithContractOnly, Boolean addEvenIfAutoDisabled) at ProtoBuf.Meta.RuntimeTypeModel.GetKey(Type type, Boolean demand, Boolean getBaseKey) Stack Trace: at ProtoBuf.Meta.RuntimeTypeModel.GetKey(Type type, Boolean demand, Boolean getBaseKey) at ProtoBuf.Meta.TypeModel.GetKey(Type& type) at ProtoBuf.Meta.TypeModel.Deserialize(Stream source, Object value, Type type) 

此致,马克

编辑添加:我定义了我的可序列化对象:

 [ProtoContract] public class Job { [ProtoMember(1)] public long JobId { get; private set; } } 

我很难在每个可序列化对象上轻松调用PrepareSerialiser,因为我在不同的命名空间中有很多。 但是考虑一下如果要求protobuf对同一类型的两个对象进行反序列化会发生什么呢?这个对象之前没有见过,类似于同一时间?

RuntimeTypeModel.Default(默认模型)是静态的,并且支持静态Serializer类(重新注释没有任何静态状态)。 尽管由于偏执而加入了这项检查,但我从未见过这个错误。 我非常希望看到一个能够重现这一点的例子。 你确定你没有穿线吗? 如果不是线程,我只能想知道:类型模型真的很大吗?

实际上,即使有许multithreading在启动时积极地攻击它(即在这里的堆栈溢出),它表现得很好。 正如错误消息提示,您可以尝试在app-startup期间调用Serializer.PrepareSerializer,这将预先初始化所有内容,避免任何线程问题。

但是嘿! 至少它没有僵局!

但是,奇怪的是它仍然不应该死锁 – 它故意使用粗锁来避免锁定它的顺序问题。 再一次 – 我真的很想看到一个样本。

老问题,但如果有人碰巧遇到此错误,请检查您正在使用的DLL版本。 在便携版本中出现此exception的可能性非常高。

便携式版本有几个与此问题相关的PR是https://github.com/mgravell/protobuf-net/pull/98和https://github.com/mgravell/protobuf-net/pull/ 114 。

我准备使用Serializers

Serializer.PrepareSerializer();

没有真正帮助我。

对我来说,解决方案(又称解决方法)是在启动时序列化类型,这会在应用启动时造成麻烦:

MessageSerialization.Serialize(new Type());

其中MessageSerialization.Serialize是使用protobuf Serializer.Serialize(stream,o)的序列化方法

我在服务器上收到同样的错误。 虽然我不确定导致错误的原因。 几天前,我们的服务器处于我们所经历的最高负载之下,它相隔几个小时发生了两次。 运行8台服务器,所有CPU的CPU在几秒钟内从70%上升到100%,但时间略有不同。 例如,每个服务器可能在第一个服务器启动后1-5分钟启动此峰值。

从来没有见过这种情况,我已经将这段代码生产了几个月。 仍然无法重现它,我无法判断错误是否被抛出,因为服务器处于100%CPU或者这是导致服​​务器出现峰值的原因。 停止与服务器的所有连接并让cpu回退到0修复了问题。 不需要iis重启。

当IIS启动时,我为每种类型运行以下代码一次。

 var type = this.GetType(); RuntimeTypeModel.Default.Add(type, true); Int32 i = 1; foreach(PropertyInfo info in type.GetProperties()) { if(info.CanWrite) { RuntimeTypeModel.Default[type].AddField(i++, info.Name); } }