Самый быстрый способ сериализации и десериализации .NET-объектов

87

Я ищу самый быстрый способ сериализации и десериализации .NET-объектов. Вот что у меня есть на данный момент:

public class TD
{
    public List<CT> CTs { get; set; }
    public List<TE> TEs { get; set; }
    public string Code { get; set; }
    public string Message { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }

    public static string Serialize(List<TD> tData)
    {
        var serializer = new XmlSerializer(typeof(List<TD>));

        TextWriter writer = new StringWriter();
        serializer.Serialize(writer, tData);

        return writer.ToString();
    }

    public static List<TD> Deserialize(string tData)
    {
        var serializer = new XmlSerializer(typeof(List<TD>));

        TextReader reader = new StringReader(tData);

        return (List<TD>)serializer.Deserialize(reader);
    }        
}
Aron
источник
2
Производительность или отпечаток кода?
ulrichb
Вы спрашиваете, нужны ли мне данные о производительности или код?
aron
3
Он спрашивает, подразумеваете ли вы под «самым быстрым способом» производительность или объем кода. BinaryFormatterчрезвычайно быстро с точки зрения кода и реализации, но такое решение, как Marc's, будет работать быстрее в тесте.
Коди Грей
хорошо, понятно, я имел в виду с точки зрения производительности ...
aron
Там много ссылок. Один из таких: blogs.msdn.com/b/youssefm/archive/2009/07/10/…
nawfal

Ответы:

57

Вот ваша модель (с изобретенным CTи TE) с использованием protobuf-net (но с сохранением возможности использования XmlSerializer, что может быть полезно - в частности, для миграции); Я смиренно подчиняться (с большим количеством доказательств , если вам это нужно) , что является самым быстрым (или , конечно , один из самых быстрых) сериализатором общего назначения в .NET.

Если вам нужны строки, просто кодируйте двоичный код base-64.

[XmlType]
public class CT {
    [XmlElement(Order = 1)]
    public int Foo { get; set; }
}
[XmlType]
public class TE {
    [XmlElement(Order = 1)]
    public int Bar { get; set; }
}
[XmlType]
public class TD {
    [XmlElement(Order=1)]
    public List<CT> CTs { get; set; }
    [XmlElement(Order=2)]
    public List<TE> TEs { get; set; }
    [XmlElement(Order = 3)]
    public string Code { get; set; }
    [XmlElement(Order = 4)]
    public string Message { get; set; }
    [XmlElement(Order = 5)]
    public DateTime StartDate { get; set; }
    [XmlElement(Order = 6)]
    public DateTime EndDate { get; set; }

    public static byte[] Serialize(List<TD> tData) {
        using (var ms = new MemoryStream()) {
            ProtoBuf.Serializer.Serialize(ms, tData);
            return ms.ToArray();
        }            
    }

    public static List<TD> Deserialize(byte[] tData) {
        using (var ms = new MemoryStream(tData)) {
            return ProtoBuf.Serializer.Deserialize<List<TD>>(ms);
        }
    }
}
Марк Гравелл
источник
2
Добрый день, Марк, вам нравится проделанная вами работа с буферами протоколов, и я знаю, что этому посту почти 5 лет, но у netserializer, цитируемого здесь в ответе (Binoj), есть показатели, указывающие, что ваша реализация не самая быстрая. Это справедливое заявление / реклама или есть компромисс? спасибо
Джереми Томпсон
хорошо, теперь я вижу, NetSerialization работает только для той же версии, в которой я ищу сериализацию с толерантной к версии
Джереми Томпсон
1
Любой, кто думает, что это быстро, должен что-то курить, этого может быть достаточно для многих случаев, и это может быть быстрее, чем многие другие сериализации, но действительно ли это быстро по сравнению с ручным анализом? Боже мой, нет.
BjarkeCK,
Сериализаторы @BjarkeCK по своей сути немного более сложны, поскольку им нужно делать много вещей, чтобы люди не отстреливались (особенно при повторении версий); большинство людей не хотят тратить свою жизнь на отладку кода сериализации, поэтому: хороший сериализатор - хотя, несомненно, медленнее, чем идеально реализованная, не терпимая к версии ручная реализация - обычно является хорошим компромиссом для большинства людей
Марк Гравелл
1
@BjarkeCK Я категорически не согласен; это даже отдаленно бесполезно для большинства людей. Что дальше - писать собственные сборники каждый день? Нет: делать это даже достаточно хорошо - сложно . Конечно, если вам действительно нужен самый быстрый вывод: вам придется запачкать руки, но для большинства людей это будет действительно пустой тратой времени. В ЛУЧШЕМУ это заняло бы гораздо больше времени. Скорее всего, их код будет содержать ошибки, ненадежен и, вероятно, медленнее, чем при использовании доступных библиотек. Большинству людей следует сосредоточиться на том, что нужно их приложению , а не на мелочах.
Марк Гравелл
33

Всестороннее сравнение различных форматов, сделанное мной в этом посте - https://maxondev.com/serialization-performance-comparison-c-net-formats-frameworks-xmldatacontractserializer-xmlserializer-binaryformatter-json-newtonsoft-servicestack-text/

Всего один образец из поста введите описание изображения здесь

Максим
источник
5
Это не скорость. Это медлительность. В статье по ссылке сказано: «Чем меньше, тем лучше».
Тимур Нуриясов 01
2
@TimurNuriyasov, именно столько времени ушло на операцию
Максим
2
Так вы говорите, что двоичный файл самый медленный? Я так не думаю! Я думаю, это правильно относится к скорости, а не ко времени.
Джавид,
2
Бинарный - самый медленный. Попробуйте сами. Но я бы сказал, что это проще всего, так как для правильной работы с полиморфными объектами (интерфейсами и т. Д.) Не требуется никаких настраиваемых разрешающих
элементов,
1
@Kamarey, посмотри на мой тест ниже ... двоичный код намного быстрее, чем другие.
Джереми Головач 01
19

Заинтересовавшись этим, я решил протестировать предложенные методы с помощью максимально приближенного теста «яблоки к яблокам». Я написал консольное приложение со следующим кодом:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace SerializationTests
{
    class Program
    {
        static void Main(string[] args)
        {
            var count = 100000;
            var rnd = new Random(DateTime.UtcNow.GetHashCode());
            Console.WriteLine("Generating {0} arrays of data...", count);
            var arrays = new List<int[]>();
            for (int i = 0; i < count; i++)
            {
                var elements = rnd.Next(1, 100);
                var array = new int[elements];
                for (int j = 0; j < elements; j++)
                {
                    array[j] = rnd.Next();
                }   
                arrays.Add(array);
            }
            Console.WriteLine("Test data generated.");
            var stopWatch = new Stopwatch();

            Console.WriteLine("Testing BinarySerializer...");
            var binarySerializer = new BinarySerializer();
            var binarySerialized = new List<byte[]>();
            var binaryDeserialized = new List<int[]>();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                binarySerialized.Add(binarySerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("BinaryFormatter: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in binarySerialized)
            {
                binaryDeserialized.Add(binarySerializer.Deserialize<int[]>(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("BinaryFormatter: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);


            Console.WriteLine();
            Console.WriteLine("Testing ProtoBuf serializer...");
            var protobufSerializer = new ProtoBufSerializer();
            var protobufSerialized = new List<byte[]>();
            var protobufDeserialized = new List<int[]>();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                protobufSerialized.Add(protobufSerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("ProtoBuf: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in protobufSerialized)
            {
                protobufDeserialized.Add(protobufSerializer.Deserialize<int[]>(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("ProtoBuf: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            Console.WriteLine();
            Console.WriteLine("Testing NetSerializer serializer...");
            var netSerializerSerializer = new ProtoBufSerializer();
            var netSerializerSerialized = new List<byte[]>();
            var netSerializerDeserialized = new List<int[]>();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                netSerializerSerialized.Add(netSerializerSerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("NetSerializer: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in netSerializerSerialized)
            {
                netSerializerDeserialized.Add(netSerializerSerializer.Deserialize<int[]>(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("NetSerializer: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            Console.WriteLine("Press any key to end.");
            Console.ReadKey();
        }

        public class BinarySerializer
        {
            private static readonly BinaryFormatter Formatter = new BinaryFormatter();

            public byte[] Serialize(object toSerialize)
            {
                using (var stream = new MemoryStream())
                {
                    Formatter.Serialize(stream, toSerialize);
                    return stream.ToArray();
                }
            }

            public T Deserialize<T>(byte[] serialized)
            {
                using (var stream = new MemoryStream(serialized))
                {
                    var result = (T)Formatter.Deserialize(stream);
                    return result;
                }
            }
        }

        public class ProtoBufSerializer
        {
            public byte[] Serialize(object toSerialize)
            {
                using (var stream = new MemoryStream())
                {
                    ProtoBuf.Serializer.Serialize(stream, toSerialize);
                    return stream.ToArray();
                }
            }

            public T Deserialize<T>(byte[] serialized)
            {
                using (var stream = new MemoryStream(serialized))
                {
                    var result = ProtoBuf.Serializer.Deserialize<T>(stream);
                    return result;
                }
            }
        }

        public class NetSerializer
        {
            private static readonly NetSerializer Serializer = new NetSerializer();
            public byte[] Serialize(object toSerialize)
            {
                return Serializer.Serialize(toSerialize);
            }

            public T Deserialize<T>(byte[] serialized)
            {
                return Serializer.Deserialize<T>(serialized);
            }
        }
    }
}

Результаты меня удивили; они были последовательными при многократном запуске:

Generating 100000 arrays of data...
Test data generated.
Testing BinarySerializer...
BinaryFormatter: Serializing took 336.8392ms.
BinaryFormatter: Deserializing took 208.7527ms.

Testing ProtoBuf serializer...
ProtoBuf: Serializing took 2284.3827ms.
ProtoBuf: Deserializing took 2201.8072ms.

Testing NetSerializer serializer...
NetSerializer: Serializing took 2139.5424ms.
NetSerializer: Deserializing took 2113.7296ms.
Press any key to end.

Собрав эти результаты, я решил посмотреть, работает ли ProtoBuf или NetSerializer лучше с более крупными объектами. Я изменил количество коллекций на 10 000 объектов, но увеличил размер массивов до 1-10 000 вместо 1-100. Результаты казались еще более определенными:

Generating 10000 arrays of data...
Test data generated.
Testing BinarySerializer...
BinaryFormatter: Serializing took 285.8356ms.
BinaryFormatter: Deserializing took 206.0906ms.

Testing ProtoBuf serializer...
ProtoBuf: Serializing took 10693.3848ms.
ProtoBuf: Deserializing took 5988.5993ms.

Testing NetSerializer serializer...
NetSerializer: Serializing took 9017.5785ms.
NetSerializer: Deserializing took 5978.7203ms.
Press any key to end.

Поэтому мой вывод таков: могут быть случаи, когда ProtoBuf и NetSerializer хорошо подходят, но с точки зрения сырой производительности, по крайней мере, для относительно простых объектов ... BinaryFormatter значительно более производительный, по крайней мере, на порядок.

YMMV.

Джереми Головач
источник
1
возможно, BinaryFormatter работает очень быстро с массивами.
Behrooz
4
Возможно ... но в указанных условиях результаты были впечатляющими. Урок здесь может заключаться в том, что не верьте, что один метод является наиболее эффективным при любых обстоятельствах. Тестирование и бенчмаркинг всегда просвещают.
Джереми Головач
В C ++ сериализация объектов примерно в 100 раз быстрее!
Mario M,
Очень интересно! Все утверждали, что protobuf самый быстрый, но это ясно показывает, что он очень медленный. Я добавил свой BinaronSerializer в смесь здесь dotnetfiddle.net/gOqQ7p - он почти в два раза быстрее, чем BinaryFormatter, который и так очень быстро работает с массивами.
Зак увидел
16

Protobuf очень-очень быстрый.

См. Http://code.google.com/p/protobuf-net/wiki/Performance для получения подробной информации о производительности этой системы и ее реализации.

Питер ван Гинкель
источник
Есть ли недостатки в использовании Protobuf?
Роберт Джеппесен
11
Вы должны аннотировать свои объекты. Protobuf не хранит имена и типы полей, как сериализаторы, а берет их из ваших реальных типов. Это одна из причин, по которой целевые файлы намного меньше. Документация все это объясняет. Я использую его уже некоторое время, и если вам нужна быстрая (де) сериализация и небольшие целевые файлы, protobuf действительно то, что вам нужно.
Питер ван Гинкель
Любой пример полного исходного кода с использованием Protobut на C # для добавления к ответу?
Kiquenet
Это не так быстро ... На самом деле, это довольно медленно по сравнению с очень-очень-очень быстрыми сериализаторами: dotnetfiddle.net/gOqQ7p
Zach Saw
@ZachSaw это не так быстро, если вы просто имеете дело с массивами целых чисел (ваш пример), но очень немногие люди сериализуют только целые числа. Вы видите преимущества в скорости (или, по крайней мере, я), когда начинаете иметь дело с вложенными сложными типами с большим количеством членов.
matt.rothmeyer,
15

Еще один сериализатор, который утверждает, что он сверхбыстрый, - это netserializer. .

Данные, приведенные на их сайте, показывают производительность 2x - 4x по сравнению с protobuf , я сам не пробовал, но если вы оцениваете различные варианты, попробуйте и это

Биной ​​Антоний
источник
3
Я только что попробовал NetSerializer в своем приложении, и он творит чудеса. Стоит попробовать.
Гален
netserializer не подходит для сериализации «пользовательских» объектов, когда библиотека не знает, с каких типов должны начинаться, или даже не имеет возможности заставить пользователя пометить свои объекты как сериализуемые.
Зак увидел
6

Бинарный сериализатор, включенный в .net, должен быть быстрее, чем XmlSerializer. Или другой сериализатор для protobuf, json, ...

Но для некоторых из них вам нужно добавить атрибуты или другой способ добавить метаданные. Например, ProtoBuf внутренне использует числовые идентификаторы свойств, и отображение необходимо каким-то образом сохранить с помощью другого механизма. Управление версиями - нетривиальная задача для любого сериализатора.

Коды
источник
Да, это действительно очень быстро и обрабатывает намного больше случаев / типов, чем Xml.
leppie
1

Я удалил ошибки в приведенном выше коде и получил следующие результаты: Также я не уверен, что NetSerializer требует от вас регистрации типов, которые вы сериализуете, какие различия в совместимости или производительности потенциально могут возникнуть.

Generating 100000 arrays of data...
Test data generated.
Testing BinarySerializer...
BinaryFormatter: Serializing took 508.9773ms.
BinaryFormatter: Deserializing took 371.8499ms.

Testing ProtoBuf serializer...
ProtoBuf: Serializing took 3280.9185ms.
ProtoBuf: Deserializing took 3190.7899ms.

Testing NetSerializer serializer...
NetSerializer: Serializing took 427.1241ms.
NetSerializer: Deserializing took 78.954ms.
Press any key to end.

Измененный код

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;

namespace SerializationTests
{
    class Program
    {
        static void Main(string[] args)
        {
            var count = 100000;
            var rnd = new Random((int)DateTime.UtcNow.Ticks & 0xFF);
            Console.WriteLine("Generating {0} arrays of data...", count);
            var arrays = new List<int[]>();
            for (int i = 0; i < count; i++)
            {
                var elements = rnd.Next(1, 100);
                var array = new int[elements];
                for (int j = 0; j < elements; j++)
                {
                    array[j] = rnd.Next();
                }
                arrays.Add(array);
            }
            Console.WriteLine("Test data generated.");
            var stopWatch = new Stopwatch();

            Console.WriteLine("Testing BinarySerializer...");
            var binarySerializer = new BinarySerializer();
            var binarySerialized = new List<byte[]>();
            var binaryDeserialized = new List<int[]>();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                binarySerialized.Add(binarySerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("BinaryFormatter: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in binarySerialized)
            {
                binaryDeserialized.Add(binarySerializer.Deserialize<int[]>(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("BinaryFormatter: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);


            Console.WriteLine();
            Console.WriteLine("Testing ProtoBuf serializer...");
            var protobufSerializer = new ProtoBufSerializer();
            var protobufSerialized = new List<byte[]>();
            var protobufDeserialized = new List<int[]>();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                protobufSerialized.Add(protobufSerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("ProtoBuf: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in protobufSerialized)
            {
                protobufDeserialized.Add(protobufSerializer.Deserialize<int[]>(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("ProtoBuf: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            Console.WriteLine();
            Console.WriteLine("Testing NetSerializer serializer...");
            var netSerializerSerialized = new List<byte[]>();
            var netSerializerDeserialized = new List<int[]>();

            stopWatch.Reset();
            stopWatch.Start();
            var netSerializerSerializer = new NS();
            foreach (var array in arrays)
            {
                netSerializerSerialized.Add(netSerializerSerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("NetSerializer: Serializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in netSerializerSerialized)
            {
                netSerializerDeserialized.Add(netSerializerSerializer.Deserialize<int[]>(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("NetSerializer: Deserializing took {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            Console.WriteLine("Press any key to end.");
            Console.ReadKey();
        }

        public class BinarySerializer
        {
            private static readonly BinaryFormatter Formatter = new BinaryFormatter();

            public byte[] Serialize(object toSerialize)
            {
                using (var stream = new MemoryStream())
                {
                    Formatter.Serialize(stream, toSerialize);
                    return stream.ToArray();
                }
            }

            public T Deserialize<T>(byte[] serialized)
            {
                using (var stream = new MemoryStream(serialized))
                {
                    var result = (T)Formatter.Deserialize(stream);
                    return result;
                }
            }
        }

        public class ProtoBufSerializer
        {
            public byte[] Serialize(object toSerialize)
            {
                using (var stream = new MemoryStream())
                {
                    ProtoBuf.Serializer.Serialize(stream, toSerialize);
                    return stream.ToArray();
                }
            }

            public T Deserialize<T>(byte[] serialized)
            {
                using (var stream = new MemoryStream(serialized))
                {
                    var result = ProtoBuf.Serializer.Deserialize<T>(stream);
                    return result;
                }
            }
        }

        public class NS
        {
            NetSerializer.Serializer Serializer = new NetSerializer.Serializer(new Type[] { typeof(int), typeof(int[]) });

            public byte[] Serialize(object toSerialize)
            {
                using (var stream = new MemoryStream())
                {
                    Serializer.Serialize(stream, toSerialize);
                    return stream.ToArray();
                }
            }

            public T Deserialize<T>(byte[] serialized)
            {
                using (var stream = new MemoryStream(serialized))
                {
                    Serializer.Deserialize(stream, out var result);
                    return (T)result;
                }
            }
        }
    }
}
Джон Хейлман
источник
1
Какие ошибки вы имеете в виду?
Джереми Головач
0

Вы можете попробовать Salar.Bois сериализатор который имеет приличную производительность. Он ориентирован на размер полезной нагрузки, но при этом обеспечивает хорошую производительность.

На странице Github есть тесты, если вы хотите увидеть и сравнить результаты самостоятельно.

https://github.com/salarcode/Bois

Салар
источник
0

Я взял на себя смелость скормить ваши классы в скормить генератор CGbR .Поскольку он находится на ранней стадии, он не поддерживает DateTime , поэтому я просто заменил его на long. Сгенерированный код сериализации выглядит так:

public int Size
{
    get 
    { 
        var size = 24;
        // Add size for collections and strings
        size += Cts == null ? 0 : Cts.Count * 4;
        size += Tes == null ? 0 : Tes.Count * 4;
        size += Code == null ? 0 : Code.Length;
        size += Message == null ? 0 : Message.Length;

        return size;              
    }
}

public byte[] ToBytes(byte[] bytes, ref int index)
{
    if (index + Size > bytes.Length)
        throw new ArgumentOutOfRangeException("index", "Object does not fit in array");

    // Convert Cts
    // Two bytes length information for each dimension
    GeneratorByteConverter.Include((ushort)(Cts == null ? 0 : Cts.Count), bytes, ref index);
    if (Cts != null)
    {
        for(var i = 0; i < Cts.Count; i++)
        {
            var value = Cts[i];
            value.ToBytes(bytes, ref index);
        }
    }
    // Convert Tes
    // Two bytes length information for each dimension
    GeneratorByteConverter.Include((ushort)(Tes == null ? 0 : Tes.Count), bytes, ref index);
    if (Tes != null)
    {
        for(var i = 0; i < Tes.Count; i++)
        {
            var value = Tes[i];
            value.ToBytes(bytes, ref index);
        }
    }
    // Convert Code
    GeneratorByteConverter.Include(Code, bytes, ref index);
    // Convert Message
    GeneratorByteConverter.Include(Message, bytes, ref index);
    // Convert StartDate
    GeneratorByteConverter.Include(StartDate.ToBinary(), bytes, ref index);
    // Convert EndDate
    GeneratorByteConverter.Include(EndDate.ToBinary(), bytes, ref index);
    return bytes;
}

public Td FromBytes(byte[] bytes, ref int index)
{
    // Read Cts
    var ctsLength = GeneratorByteConverter.ToUInt16(bytes, ref index);
    var tempCts = new List<Ct>(ctsLength);
    for (var i = 0; i < ctsLength; i++)
    {
        var value = new Ct().FromBytes(bytes, ref index);
        tempCts.Add(value);
    }
    Cts = tempCts;
    // Read Tes
    var tesLength = GeneratorByteConverter.ToUInt16(bytes, ref index);
    var tempTes = new List<Te>(tesLength);
    for (var i = 0; i < tesLength; i++)
    {
        var value = new Te().FromBytes(bytes, ref index);
        tempTes.Add(value);
    }
    Tes = tempTes;
    // Read Code
    Code = GeneratorByteConverter.GetString(bytes, ref index);
    // Read Message
    Message = GeneratorByteConverter.GetString(bytes, ref index);
    // Read StartDate
    StartDate = DateTime.FromBinary(GeneratorByteConverter.ToInt64(bytes, ref index));
    // Read EndDate
    EndDate = DateTime.FromBinary(GeneratorByteConverter.ToInt64(bytes, ref index));

    return this;
}

Я создал список таких объектов-примеров:

var objects = new List<Td>();
for (int i = 0; i < 1000; i++)
{
    var obj = new Td
    {
        Message = "Hello my friend",
        Code = "Some code that can be put here",
        StartDate = DateTime.Now.AddDays(-7),
        EndDate = DateTime.Now.AddDays(2),
        Cts = new List<Ct>(),
        Tes = new List<Te>()
    };
    for (int j = 0; j < 10; j++)
    {
        obj.Cts.Add(new Ct { Foo = i * j });
        obj.Tes.Add(new Te { Bar = i + j });
    }
    objects.Add(obj);
}

Результаты на моей машине в Releaseсборке:

var watch = new Stopwatch();
watch.Start();
var bytes = BinarySerializer.SerializeMany(objects);
watch.Stop();

Размер: 149000 байт

Время: 2,059 мс 3,13 мс

Изменить: начиная с CGbR 0.4.3 двоичный сериализатор поддерживает DateTime. К сожалению, этот DateTime.ToBinaryметод безумно медленный. Я скоро заменю его чем-нибудь более быстрым.

Edit2: при использовании UTC DateTimeпутем вызова ToUniversalTime()производительности восстанавливается и частота составляет 1,669 мс .

Токсантрон
источник