2013-05-28 4 views
1

Я обновил старую версию protobuf до текущей в огромном проекте (используемая версия составляет около 1-2 лет. Я не знаю rev). К сожалению новая версия бросает исключениеenum serialization with protobuf-net

CreateWireTypeException в ProtoReader.cs линии 292

в следующем тесте:

enum Test 
    { 
     test1 = 0, 
     test2 
    }; 
    static public void Test1() 
    { 
     Test original = Test.test2; 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      Serializer.SerializeWithLengthPrefix<Test>(ms, original, PrefixStyle.Fixed32, 1); 
      ms.Position = 0; 
      Test obj; 
      obj = Serializer.DeserializeWithLengthPrefix<Test>(ms, PrefixStyle.Fixed32); 
     } 
    } 

я узнал перечислений не предполагается сериализовать напрямую вне класса, но наша система слишком велика, чтобы просто перевернуть все перечисления в классах. Есть ли другие решения этой проблемы? Он отлично работает с Serialize и Deserialize только исключениями DeserializeWithLengthPrefix.

Тестовая лаборатория отлично работает в старых версиях, например. r262 протобуф-сети.

ответ

3

Просто ошибка; это фиксируется в R640 (в настоящее время развернуты как NuGet и Google-код), а также с дополнительным испытанием на основе кода выше, так что он не может ползти обратно в


производительности Re (комментарии). первый намек, на который я смотрел бы: «предпочитаю группы». В основном, спецификация protobuf включает в себя два разных способа включения под-объектов - «группы» и «префикс длины». Группы были оригинальной версией, но google теперь двигаются в направлении «префикс длины» и пытаются посоветовать людям не использовать «группы». Однако! Из-за того, как работает protobuf-net, «группы» на самом деле заметно дешевле писать; это потому, что в отличие от реализации Google, protobuf-net делает не Знайте заранее. Это означает, что писать длину префикса, это нужно сделать один из:

  • вычислить длину (почти столько работы, как на самом деле сериализации данные, бутон добавляет целую копию кода) по мере необходимости; написать длину, то фактически сериализовать Полученные данные
  • сериализации в буфер, записать длину, написать буфер
  • оставить место держатель, сериализации, затем петлю назад и записать фактическую длину в место держателя , при необходимости отрегулировать прокладку

Я использовал все три подхода в разное время, но v2 использует третий вариант. Я продолжаю играть с добавлением 4-ем реализации:

  • оставить место держателя, сериализация, затем цикла обратно и записать фактическую длину , используя сверхдолгую форму (поэтому никаких корректировок обивки никогда не требуется)

, но ... консенсус, по-видимому, заключается в том, что «сложная форма» немного рискованна; Тем не менее, это будет хорошо работать для protobuf-net до protobuf-net.

Но как вы можете видеть: длина-префикс всегда имеет некоторые накладные расходы. Теперь представьте довольно глубоко вложенные объекты, и вы увидите несколько бликов.Группы работают по-разному; формат кодирования для группы:

  • написать маркер начала; сериализации; напишите конечный маркер

это он; нет необходимости в длине; действительно, действительно, очень дешево писать. На проводнике основное различие между ними:

  • группы: дешево писать, но вы не можете пропустить их, если встретите их как неожиданные данные; Вы должны проанализировать заголовки полезной нагрузки
  • длина префикса: дороже писать, но дешево, чтобы пропустить, если вы столкнулись с ним, как неожиданные данные - вы просто прочитать длину и копировать/перемещать, что много байт

Но! слишком подробно!

Что это значит для вас? Ну, представьте, у вас есть:

[ProtoContract] 
public class SomeWrapper 
{ 
    [ProtoMember(1)] 
    public List<Person> People { get { return people; } } 

    private readonly List<Person> people = new List<Person>(); 
} 

Вы можете сделать супер сложное изменение:

[ProtoContract] 
public class SomeWrapper 
{ 
    [ProtoMember(1, DataFormat=DataFormat.Group)] 
    public List<Person> People { get { return people; } } 

    private readonly List<Person> people = new List<Person>(); 
} 

, и он будет использовать более дешевую схему кодирования. Все ваши существующие данные будут в порядке, если вы используете protobuf-net.

+0

Спасибо :) Отлично работает сейчас. И похоже, что новая версия намного быстрее старой. Отличная работа! :) – luz

+0

кстати. есть ли у вас какие-либо рекомендации по оптимизации прото-buf для максимальной скорости? Я работаю на сервере .net, и сериализация по-прежнему далеко в наших профилирующих данных, и каждый мс стоит исправлять для нас. – luz

+1

@luz, который будет немного зависеть от модели; использование «группового» формата для под-объектов - большая помощь - это позволяет избежать необходимости буферизации или исправления; и что касается protobuf-net, то переключение между ними - это не ** изменение обрыва - любые старые данные все равно будут работать нормально (другие реализации, вероятно, не будут так прощать). Я также хотел бы спросить: ваше приложение «запускает, делает что-то, выключает», или «запускается ли, работает веками много дел»? Причина, по которой я спрашиваю, заключается в том, что * default * должен выполнять метапрограммирование при необходимости, что добавляет несколько мс к * первому * использованию для каждого типа, но –