Moyen le plus rapide pour sérialiser et désérialiser des objets .NET

87

Je recherche le moyen le plus rapide de sérialiser et de désérialiser des objets .NET. Voici ce que j'ai jusqu'à présent:

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
la source
2
Performance ou empreinte de code?
ulrichb
Me demandez-vous si j'ai besoin de données de performance ou d'un code?
aron
3
Il demande si, par «moyen le plus rapide», vous entendez en termes de performances ou en termes d'empreinte de code. BinaryFormatterest extrêmement rapide en termes de code et d'implémentation, mais une solution comme celle de Marc sera plus rapide dans un benchmark.
Cody Gray
ok, je vois, je voulais dire en termes de performances ...
aron
Il existe de nombreux liens. Un tel: blogs.msdn.com/b/youssefm/archive/2009/07/10/…
nawfal

Réponses:

57

Voici votre modèle (avec inventé CTet TE) utilisant protobuf-net (tout en conservant la possibilité d'utiliser XmlSerializer, ce qui peut être utile - en particulier pour la migration); Je soumets humblement (avec beaucoup de preuves si vous en avez besoin) qu'il s'agit du sérialiseur généraliste le plus rapide (ou certainement l'un des plus rapides) de .NET.

Si vous avez besoin de chaînes, encodez simplement le binaire en 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);
        }
    }
}
Marc Gravell
la source
2
G'day Marc, j'adore le travail que vous avez effectué sur les tampons de protocole et je sais que cet article a presque 5 ans mais le netserializer cité dans une réponse ici (Binoj) a des métriques indiquant que votre implémentation n'est pas la plus rapide. Est-ce une déclaration / publicité juste ou y a-t-il un compromis? merci
Jeremy Thompson
ok je vois maintenant, NetSerialization ne fonctionne que pour la même version où je recherche la sérialisation à tolérance de version
Jeremy Thompson
1
Quiconque pense que c'est rapide doit fumer quelque chose, cela peut être assez rapide dans de nombreux cas, et cela peut être plus rapide que beaucoup d'autres sérialisations, mais est-ce vraiment rapide, par rapport à l'analyse manuelle? Mon dieu non.
BjarkeCK
Les sérialiseurs @BjarkeCK sont intrinsèquement un peu plus impliqués, car ils doivent faire beaucoup de choses pour empêcher les gens de se tirer dessus (surtout lorsqu'ils itèrent des versions); la plupart des gens ne veulent pas passer leur vie à déboguer le code de sérialisation, donc: un bon sérialiseur - bien que sans aucun doute plus lent qu'une implémentation manuelle parfaitement implémentée et intolérante aux versions - est généralement un bon compromis pour la plupart des gens
Marc Gravell
1
@BjarkeCK Je ne suis pas du tout d'accord; ce n'est même pas utile à distance pour la plupart des gens. Et ensuite - écrire nos propres collections chaque jour? Non: faire ce truc, même raisonnablement bien, est difficile . Bien sûr, si vous avez réellement besoin de la sortie la plus rapide: vous allez devoir vous salir les mains - mais pour la plupart des gens, faire cela serait une très mauvaise perte de temps. Au mieux, cela leur prendrait beaucoup plus de temps. Plus probablement, leur code serait bogué, peu fiable et probablement plus lent que l'utilisation des bibliothèques disponibles. La plupart des gens devraient se concentrer sur ce dont leur application a besoin , pas sur ces détails.
Marc Gravell
33

Une comparaison complète entre différents formats faite par moi dans ce post- https://maxondev.com/serialization-performance-comparison-c-net-formats-frameworks-xmldatacontractserializer-xmlserializer-binaryformatter-json-newtonsoft-servicestack-text/

Juste un échantillon du post- entrez la description de l'image ici

Maxime
la source
5
Ce n'est pas de la vitesse. C'est de la lenteur. Il dit "plus petit est meilleur" dans l'article lié.
Timur Nuriyasov
2
@TimurNuriyasov, c'est le temps qu'il a fallu pour faire l'opération
Maxim
2
Alors vous dites que le binaire est le plus lent? Je ne pense pas! Je suppose que cela fait correctement référence à la vitesse, pas au temps.
Javid
2
Le binaire est le plus lent. Essayez vous-même. Mais je dirais que c'est le plus simple, car il ne nécessite aucun élément de résolution personnalisé pour fonctionner correctement avec des objets polymorphes (interfaces, etc.)
Kamarey
1
@Kamarey regarde mon test ci-dessous ... le binaire est bien plus rapide que les autres.
Jeremy Holovacs
19

S'intéressant à cela, j'ai décidé de tester les méthodes suggérées avec le test «pommes aux pommes» le plus proche possible. J'ai écrit une application console, avec le code suivant:

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);
            }
        }
    }
}

Les résultats m'ont surpris; ils étaient cohérents lorsqu'ils étaient exécutés plusieurs fois:

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.

En rassemblant ces résultats, j'ai décidé de voir si ProtoBuf ou NetSerializer fonctionnait mieux avec des objets plus volumineux. J'ai changé le nombre de collections à 10 000 objets, mais j'ai augmenté la taille des tableaux à 1 à 10 000 au lieu de 1 à 100. Les résultats semblaient encore plus définitifs:

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.

Ma conclusion est donc la suivante: il peut y avoir des cas où ProtoBuf et NetSerializer sont bien adaptés, mais en termes de performances brutes pour au moins des objets relativement simples ... BinaryFormatter est nettement plus performant, d'au moins un ordre de grandeur.

YMMV.

Jeremy Holovacs
la source
1
peut-être que BinaryFormatter est vraiment très rapide avec les tableaux.
Behrooz
4
C'est possible ... mais dans les conditions évoquées, les résultats ont été spectaculaires. La leçon ici pourrait simplement être: ne croyez pas qu'une méthode est la plus performante dans toutes les circonstances. Les tests et l'analyse comparative éclairent toujours.
Jeremy Holovacs
En C ++, la sérialisation des objets est environ 100 fois plus rapide!
Mario M le
Très intéressant! Tout le monde a affirmé que Protobuf était le plus rapide, mais cela montre clairement qu'il est extrêmement lent. J'ai ajouté mon BinaronSerializer au mélange ici dotnetfiddle.net/gOqQ7p - c'est presque deux fois plus rapide que BinaryFormatter, qui est déjà très rapide avec les tableaux.
Zach Saw
16

Protobuf est très très rapide.

Consultez http://code.google.com/p/protobuf-net/wiki/Performance pour obtenir des informations détaillées sur les performances de ce système et une mise en œuvre.

Pieter van Ginkel
la source
Y a-t-il des inconvénients à utiliser Protobuf?
Robert Jeppesen
11
Vous devez annoter vos objets. Protobuf ne stocke pas les noms de champs et les types comme le font les sérialiseurs, mais les prend à partir de vos types réels. C'est l'une des raisons pour lesquelles les fichiers cibles sont beaucoup plus petits. La documentation explique tout cela. Je l'utilise depuis un certain temps maintenant, et si vous avez besoin d'une (dé) sérialisation rapide et de petits fichiers cibles, protobuf est vraiment la voie à suivre.
Pieter van Ginkel
Un exemple de code source complet utilisant Protobut en C # pour ajouter à la réponse?
Kiquenet
Ce n'est pas si rapide ... En fait, c'est assez lent comparé aux sérialiseurs très très très très rapides: dotnetfiddle.net/gOqQ7p
Zach Saw
@ZachSaw ce n'est pas aussi rapide si vous traitez uniquement avec des tableaux d'entiers (votre exemple), mais très peu de gens ne sérialisent que des entiers. Vous voyez les avantages de la vitesse (ou du moins je le fais), lorsque vous commencez à traiter des types complexes imbriqués avec beaucoup de membres.
matt.rothmeyer
15

Un autre sérialiseur qui prétend être super rapide est netserializer .

Les données fournies sur leur site montrent des performances de 2x - 4x sur protobuf , je ne l'ai pas essayé moi-même, mais si vous évaluez diverses options, essayez ceci aussi

Binoj Antony
la source
3
Je viens d'essayer NetSerializer dans mon application et cela fonctionne à merveille. Cela vaut la peine d'essayer.
Galen
netserializer ne convient pas pour sérialiser des objets "utilisateur" où la bibliothèque ne sait pas par quels types sont au départ, ou même avoir la possibilité de forcer l'utilisateur à marquer leurs objets comme sérialisables.
Zach Saw
6

Le sérialiseur binaire inclus avec .net doit être plus rapide que XmlSerializer. Ou un autre sérialiseur pour protobuf, json, ...

Mais pour certains d'entre eux, vous devez ajouter des attributs ou une autre façon d'ajouter des métadonnées. Par exemple, ProtoBuf utilise des ID de propriété numériques en interne, et le mappage doit être d'une manière ou d'une autre conservé par un mécanisme différent. Le contrôle de version n'est pas simple avec un sérialiseur.

CodesInChaos
la source
Oui, il est en effet très rapide, et il gère beaucoup plus de cas / types que le Xml.
leppie
1

J'ai supprimé les bogues dans le code ci-dessus et j'ai obtenu les résultats ci-dessous: De plus, je ne suis pas sûr de savoir comment NetSerializer vous oblige à enregistrer les types que vous sérialisez, le type de compatibilité ou les différences de performances que cela pourrait potentiellement entraîner.

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.

Code modifié

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;
                }
            }
        }
    }
}
John Heilman
la source
1
De quels bugs parlez-vous?
Jeremy Holovacs
0

Vous pouvez essayer le sérialiseur Salar.Bois qui a une performance décente. Il se concentre sur la taille de la charge utile, mais il offre également de bonnes performances.

Il y a des repères dans la page Github si vous souhaitez voir et comparer les résultats par vous-même.

https://github.com/salarcode/Bois

Salar
la source
0

J'ai pris la liberté d'alimenter vos classes dans le générateur CGbR .Parce qu'il est à un stade précoce, il ne supporte pas DateTime encore en , alors je l'ai simplement remplacé par long. Le code de sérialisation généré ressemble à ceci:

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;
}

J'ai créé une liste d'exemples d'objets comme celui-ci:

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);
}

Résultats sur ma machine en Releasebuild:

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

Taille: 149000 octets

Temps: 2,059 ms 3,13 ms

Edit: À partir de CGbR 0.4.3, le sérialiseur binaire prend en charge DateTime. Malheureusement, la DateTime.ToBinaryméthode est incroyablement lente. Je vais bientôt le remplacer par quelque chose de plus rapide.

Edit2: lors de l'utilisation de UTC DateTimeen invoquant ToUniversalTime()les performances sont restaurées et horloges à 1,669ms .

Toxantron
la source