Производительность protobuf-net против DataContractSerializer по WCF

Я тестировал сериализацию protobuf, и кажется, что для меньшего количества объектов она медленнее, чем обычная сериализация контрактов данных. Размер передачи больше при использовании DataContractSerializer, но во время сериализации и десериализации быстрее использовать DataContractSerializer

Как вы думаете, это нормально или я ошибся?

[DataContract]
public partial class Toto
{
    [DataMember]
    public string NomToto { get; set; }

    [DataMember]
    public string PrenomToto { get; set; }
} 

вот мой класс для datacontract, это то же самое для protobuf

[ProtoContract]
public partial class Titi
{
    [ProtoMember(1)]
    public string NomTiti { get; set; }

    [ProtoMember(2)]
    public string PrenomTiti { get; set; }
}

вот мои методы для служб WCF с protobuf (то же самое для контракта данных без ms)

public class TitiService : ITitiService
{
    public byte[] GetAllTitis()
    {
        List<Titi> titiList = new List<Titi>();
        for (int i = 0; i < 20000; i++)
        {
            var titi = new Titi
            {
                NomTiti = "NomTiti" + i,
                PrenomTiti = "PrenomTiti" + i
            };
            titiList.Add(titi);
        }
        var ms = new MemoryStream();
        Serializer.Serialize(ms, titiList);

        byte[] arr = ms.ToArray();
        return arr;
    }
}

Услуга с датаконтрактом

public class TotoService : ITotoService
{
    public List<Toto> GetAllTotos()
    {
        List<Toto> totoList = new List<Toto>();
        for (int i = 0; i<20000; i++)
        {
            var toto = new Toto
            {
                NomToto = "NomToto" + i,
                PrenomToto = "PrenomToto" + i
            };
            totoList.Add(toto);
        }
        return totoList;
    }
}

вот звонок клиента

    public partial class Program
{
    static ProtobufTestAzure.Client.TitiService.TitiServiceClient TitiClient;
    static ProtobufTestAzure.Client.TotoService.TotoServiceClient TotoClient;

    public static void Main(string[] args)
    {
        Stopwatch stopwatch1 = new Stopwatch();
        Stopwatch stopwatch2 = new Stopwatch();
        Stopwatch stopwatch3 = new Stopwatch();

        stopwatch1.Start();

        TitiClient = new ProtobufTestAzure.Client.TitiService.TitiServiceClient();
        Byte[] titiByte = TitiClient.GetAllTitis();
        TitiClient.Close();

        stopwatch1.Stop();


        stopwatch2.Start();

        var ms = new MemoryStream(titiByte);
        List<Titi> TitiList = Serializer.Deserialize<List<Titi>>(ms);

        stopwatch2.Stop();

        Console.WriteLine(" ");

        stopwatch3.Start();

        TotoClient = new ProtobufTestAzure.Client.TotoService.TotoServiceClient();
        var TotoList = TotoClient.GetAllTotos();
        TotoClient.Close();

        stopwatch3.Stop();

        Console.WriteLine("Time elapse for reception (Protobuf): {0} ms ({1} éléments)", stopwatch1.ElapsedMilliseconds, TitiList.Count);
        Console.WriteLine("Time elapse for deserialization (Protobuf : {0} ms ({1} éléments)", stopwatch2.ElapsedMilliseconds, TitiList.Count);
        Console.WriteLine("Time elapse for réception (Datacontract Serialization) : {0} ms ({1} éléments)", stopwatch3.ElapsedMilliseconds, TotoList.Count);

        Console.ReadLine();
    }
}

и результат для 10000 объектов

Время приема (Protobuf): 3359 мс (10000 элементов) Время десериализации (Protobuf): 138 мс (10000 элементов) Время приема (Datacontract Serialization): 2200 мс (10000 элементов)

Я тестирую его на 20000 объектах. Он дал мне первый звонок.

Время для приема (Protobuf): 11258 мс (20000 элементов) Время для десериализации (Protobuf): 133 мс (20000 элементов) Время для приема (Datacontract Serialization): 3726 мс (20000 элементов)

на второй звонок

Время для приема (Protobuf): 2844 мс (20000 элементов) Время для десериализации (Protobuf): 141 мс (20000 элементов) Время для приема (Datacontract Serialization): 7541 мс (20000 элементов)

для третьего

Время для приема (Protobuf): 2767 мс (20000 элементов) Время для десериализации (Protobuf): 145 мс (20000 элементов) Время для приема (Datacontract Serialization): 3989 мс (20000 элементов)

После активации MTOM на «Protobuf transfert» мне выдали:

для первого звонка

Время для приема (Protobuf): 3316 мс (20000 элементов) Время для десериализации (Protobuf): 63 мс (20000 элементов) Время для приема (Datacontract Serialization): 3769 мс (20000 элементов)

для второго звонка

Время для приема (Protobuf): 2279 мс (20000 элементов) Время для десериализации (Protobuf): 57 мс (20000 элементов) Время для приема (Datacontract Serialization): 3959 мс (20000 элементов)

Я добавляю эту часть кода для размера объектов

            long totoSize = new long();
        using (Stream s = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(s, totoList);
            totoSize = s.Length;
        }

        long titiSize = titiByte.Count();

он дал мне 637780 с protobuf и 1038236 с DataContractSerializer. Продолжительность вызова лучше и стабильнее этим утром. первый вызов protobuf = 2498 мс. datacontract = 5085 мс.

второй вызов protobuf = 3649 мс, дата контракта = 3840 мс

третий вызов protobuf = 2498 мс, дата контракта = 5085 мс


person Ange    schedule 26.04.2011    source источник
comment
Как вы можете ожидать, что кто-то скажет вам, если вы допустили ошибку, не показывая, что вы на самом деле сделали, например, показывая код, который вы тестировали (две его версии)?   -  person Darin Dimitrov    schedule 26.04.2011
comment
Не могли бы вы опубликовать свой метод и код, если он существует, для тестирования?   -  person Jordan    schedule 26.04.2011
comment
кстати, обычная сериализация XML! = сериализация контракта данных; они связаны, но очень разные. Но я повторяю вышесказанное; без дополнительного контекста это невозможно комментировать.   -  person Marc Gravell    schedule 26.04.2011
comment
извините за ошибку с сериализацией XML и сериализацией Datacontract, я использую последний, я редактирую с помощью своего кода   -  person Ange    schedule 26.04.2011
comment
Возможно мешают эффекты разминки. т.е. первое соединение дороже, чем последующие, потому что что-то нужно инициализировать.   -  person CodesInChaos    schedule 26.04.2011
comment
Добавьте вызов обеих служб в начало кода.   -  person CodesInChaos    schedule 26.04.2011
comment
Я повторно размещаю свой проект на лазурном, первый тест, который я сделал, был для 10000 объектов, я протестирую его с 20000, я дам вам результаты через пять минут с большим количеством вызовов   -  person Ange    schedule 26.04.2011
comment
правильно; сейчас мы говорим - я бегло посмотрю и вернусь к вам (я автор protobuf-net, кстати)   -  person Marc Gravell    schedule 26.04.2011
comment
Я знаю это Марк, я просто редактирую результаты с вызовом 20000 объектов и protobuf лучше после первого вызова   -  person Ange    schedule 26.04.2011
comment
@Ange - каким транспортом ты пользуешься из любопытства?   -  person Marc Gravell    schedule 26.04.2011
comment
@Ange - кстати, вы можете использовать Serializer.PrepareSerializer<Titi>() где-нибудь во время запуска приложения, если хотите минимизировать любые отложенные затраты.   -  person Marc Gravell    schedule 26.04.2011
comment
@Marc Я использую по умолчанию (BasicHttpBinding) Я не настраиваю web.config, я посмотрю на Serializer.PrepareSerializer ‹Titi› ()   -  person Ange    schedule 26.04.2011
comment
@Ange - круто, это моя любимая привязка; можно включить MTOM? (см. messageEncoding: msdn.microsoft.com/en-us/library/ms731361. aspx)   -  person Marc Gravell    schedule 26.04.2011
comment
@Marc Я редактирую свой первый пост с результатами MTOM, но мне неудобно использовать web.config, скажите мне, если вам нужен мой.   -  person Ange    schedule 26.04.2011
comment
@Ange - цифры немного странно скачут, мне нравится. Но: мы смотрим на что, 60 мсек на десериализацию 20 тыс. Элементов; По 3 микросекунды; это чертовски быстро по любым меркам - в этот момент я бы вместо этого начал измерять размер полезной нагрузки - посмотрю, сможете ли вы уловить это в кб / МБ / и т. д. Похоже, что скорость сети непредсказуема, так что, может быть, лучше беспокоиться о размере?   -  person Marc Gravell    schedule 26.04.2011
comment
@Marc Я редактирую свое сообщение с размером объектов для protobuf и datraContractSerializer   -  person Ange    schedule 27.04.2011
comment
@Marc Я тестирую его с WireShark, он дал мне около 700 Ko для protobuf и 2Mo для dataContractSerializer, какая хорошая работа вы сделали   -  person Ange    schedule 27.04.2011


Ответы (1)


Некоторые факторы, влияющие на производительность:

  • is the serializer prepared? This is automatic on the first use per-type; the first time through, it needs to do quite a bit of inspection etc to figure out how your model works. You can offset this by calling Serializer.PrepareSerializer<YourType>() somewhere during startup
    • or as an alternative, in v2 (available as "alpha") you can pre-generate the serializer as a dll if you need the fastest possible cold-start performance
  • what is the transport? in particular with WCF, you need to keep in mind how your byte[] is encoded (this isn't a problem on sockets, of course); for example, can the transport use MTOM? or is it base-64 encoding the byte[]?
    • and note also that it is possible that Stream and byte[] are handled differently; if you can measure the bandwidth, you might want to try both
    • basic-http с включенным MTOM я предпочитаю транспортировать WCF, если ваша цель - абсолютная скорость; или сокеты, если вы хотите приблизиться к пределу
person Marc Gravell    schedule 26.04.2011