C# Protobuf.net异常-检查元数据时超时

C# Protobuf.net异常-检查元数据时超时,c#,deadlock,protobuf-net,C#,Deadlock,Protobuf Net,在尝试使用protobuf.net反序列化对象时,有时会收到以下异常。我很惊讶,因为我从来没有超过一个线程同时反序列化同一个对象,protobuf.net源代码似乎没有使用任何静态对象进行反序列化。例外情况确实提出了一个解决方案,但我不确定如何实施,因此欢迎举个例子 Base Exception Type: System.TimeoutException: Timeout while inspecting metadata; this may indicate a deadlock. This

在尝试使用protobuf.net反序列化对象时,有时会收到以下异常。我很惊讶,因为我从来没有超过一个线程同时反序列化同一个对象,protobuf.net源代码似乎没有使用任何静态对象进行反序列化。例外情况确实提出了一个解决方案,但我不确定如何实施,因此欢迎举个例子

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(默认模型)是静态的,并且支持静态序列化器类(即没有任何静态状态的注释)。尽管由于偏执狂而添加了此检查,但我从未看到出现此错误。我绝对希望看到一个能重新证明这一点的例子。你确定你没有穿线吗?如果不是线程,我只能想:类型模型真的很大吗

事实上,即使许多线程在启动时攻击它(即在stackoverflow上),它仍然表现良好。正如错误消息所提示的,您可以尝试在应用程序启动期间调用Serializer.PrepareSerializer,这将预初始化所有内容,避免任何线程问题

但是嘿!至少它没有死锁


然而,奇怪的是,它仍然不可能死锁——它故意使用一个粗糙的锁来避免从它获得锁的顺序中出现问题。再一次-我真的很想看到一个示例。

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

以前从未见过这种情况,我已经在生产中使用了几个月的代码。仍然无法重现它,我无法判断是否是因为服务器的CPU为100%而抛出错误,或者这是导致服务器出现峰值的原因。停止与服务器的所有连接并让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);
    }
}

旧问题,但如果有人碰巧遇到此错误,请检查您正在使用的DLL版本。这个异常在便携版本中出现的几率非常高


与此问题相关的可移植版本有两个PRs,分别是和。

供我使用

Serializer.PrepareSerializer()

并没有真正帮助我

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

MessageSerialization.Serialize(新类型())


其中MessageSerialization.Serialize是使用protobuf Serializer.Serialize(stream,o)的序列化方法。如果我能可靠地重现这个问题,我肯定会提供更多的信息。不幸的是,这种情况发生在这样一小部分(0.01%)的案例中,很难确定。我序列化的所有对象都相对较小,可能有10个值类型和几个列表。我会找出我可以在哪里添加prepareSerializer调用,并让您知道问题是否仍然存在。我非常感兴趣。。。我将尝试浏览代码以查找可能导致此问题的任何内容(顺便说一句,感谢您提供完整的堆栈跟踪,这很有帮助)。这是。。。。奇怪。值得补充的是,虽然我只有一个线程反序列化一个唯一的字节[],但我可能有多达100个线程同时反序列化100个唯一的字节[]。这可能是一个与CPU负载有关的问题,即开始反序列化和结束之间的时间太长?@MarcF-作为一个随机事件,您是否可以尝试将
RuntimeTypeModel.Default.MetadataTimeOutMillicles
设置为非常大的值,只是想看看这是否是一个真正的僵局,而不是比正常情况需要更长的时间?很抱歉,这个回复花了这么长时间。我刚刚浏览了一些我的旧帖子。我确实将MetadataTimeOutMillistics增加到了“150000”,并且我认为从那以后我没有看到错误。我只是想补充一下,我也遇到了这个错误。。在数千次测试中只有一次,但我确实有多个线程在做这项工作。(4个atm,但会随着更多东西的出现而增长)这发生在我在所有内核上执行CPU限制工作时。我的整个机器都很慢。许多线程试图获取锁,其中一个线程处于某种“编译”方法中。@AgileJon如果要完全消除它,您可以使用单独的预编译器exe生成一个序列化dll,然后再也不需要执行任何元数据检查。在线程环境中,我在2.0.0.640 PCL库中体验到了这一点。在更高级别的项目中添加对显式版本的引用可以解决这个问题,方法是将PCL版本替换为特定于更高级别程序集(SL、.Net 40等)的版本,这立即解决了问题。这个答案和注释为我节省了大量时间。非常好的洞察力,朋友们。这个错误在PCL版本2.0.0.668中经常出现。我也尝试过提高上面提到的@MarcGravel的超时时间,但这并不能解决问题。除了在2016年切换到相应的CLR特定版本的.DLL?之外,还有什么线索仍然是问题所在。我在一次部署中意外地用PCL版本替换了普通的2.0.0.668,并立即