Исключение Protobuf.net - Тайм-аут при проверке метаданных - PullRequest
8 голосов
/ 10 сентября 2011

Я иногда получаю следующее исключение при попытке десериализации объекта с использованием 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 попросят десериализовать два объекта одного типа, типа, который он не видел раньше, в одно и то же время?

Ответы [ 4 ]

9 голосов
/ 06 августа 2013

Старый вопрос, но если кто-то получит эту ошибку, проверьте версию DLL, которую вы используете.Шансы на появление этого исключения в портативной версии очень высоки.

Существует несколько PR, связанных с этой проблемой с портативной версией, которые https://github.com/mgravell/protobuf-net/pull/98 и https://github.com/mgravell/protobuf-net/pull/114.

2 голосов
/ 05 февраля 2016

Для меня подготовка сериализаторов с использованием

Serializer.PrepareSerializer<Type>();

мне не очень помогла.

Для меня решение (или обходной путь) заключалось в сериализации типа при запускечто вызывало проблемы при запуске приложения:

MessageSerialization.Serialize(new Type());

Где MessageSerialization.Serialize - метод сериализации с использованием protobuf Serializer.Serialize (stream, o)

2 голосов
/ 10 сентября 2011

RuntimeTypeModel.Default (модель по умолчанию) является статическим и поддерживает статический класс Serializer (примечание, что статического состояния не было).Несмотря на добавление этой проверки из-за паранойи, у меня никогда не возникало этой ошибки.Я бы очень хотел увидеть пример, который будет это повторять.Вы уверены, что не нанизываете?Если не для многопоточности, я могу только задаться вопросом: действительно ли модель типов действительно действительно большая?

Действительно, даже при том, что многие потоки агрессивно ударили по ней при запуске (т.е. здесь, в stackoverflow), этохорошо себя ведетКак подсказывает сообщение об ошибке, вы можете попытаться вызвать Serializer.PrepareSerializer во время запуска приложения, который будет предварительно инициализировать все, избегая проблем с потоками.

Но эй!По крайней мере, она не зашла в тупик!

Странно здесь то, что все еще не должно быть возможным для тупика- он намеренно использует грубую блокировку, чтобы избежать проблем с порядком, в котором она блокируется.Опять же - я бы очень хотел увидеть образец.

1 голос
/ 15 ноября 2011

Я получаю точно такую ​​же ошибку на своих серверах.Хотя я не уверен, что является причиной ошибки.Несколько дней назад это происходило два раза в несколько часов, в то время как наши серверы находились под самой высокой нагрузкой, которую мы испытывалиЗапустив 8 серверов, загрузка ЦП на всех них выросла с 70% до 100% за секунды, но немного по-другому.Например, каждый из серверов мог запустить этот скачок через 1-5 минут после первого.

Никогда не видел, чтобы это случилось раньше, и у меня был этот код в производстве в течение нескольких месяцев.Я до сих пор не смог воспроизвести его, и я не могу сказать, сгенерирована ли ошибка, потому что на сервере загружен процессор на 100% или это вызвало скачок на сервере.Прекращение всех подключений к серверам и возвращение процессора к нулю устранило проблему.Перезагрузка 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);
    }
}
...