95 votes

Moyen le plus rapide de sérialiser et désérialiser les objets .NET

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

public class TD
{
    public List CTs { get; set; }
    public List 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 tData)
    {
        var serializer = new XmlSerializer(typeof(List));

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

        return writer.ToString();
    }

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

        TextReader reader = new StringReader(tData);

        return (List)serializer.Deserialize(reader);
    }        
}

2 votes

Performance ou empreinte de code?

0 votes

Est-ce que tu me demandes si j'ai besoin de données de performance ou de code?

3 votes

Il demande si, par "le moyen le plus rapide", vous entendez en termes de performance ou en termes d'empreinte de code. BinaryFormatter est extrêmement rapide en termes de code et d'implémentation, mais une solution comme celle de Marc sera plus performante dans un test de référence.

59voto

Marc Gravell Points 482669

Voici votre modèle (avec CT et TE inventés) utilisant protobuf-net (tout en conservant la capacité 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) que c'est le plus rapide (ou certainement l'un des plus rapides) sérialiseurs à usage général dans .NET.

Si vous avez besoin de chaînes, encodez simplement en base 64 le binaire.

[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 CTs { get; set; }
    [XmlElement(Order=2)]
    public List 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 tData) {
        using (var ms = new MemoryStream()) {
            ProtoBuf.Serializer.Serialize(ms, tData);
            return ms.ToArray();
        }            
    }

    public static List Deserialize(byte[] tData) {
        using (var ms = new MemoryStream(tData)) {
            return ProtoBuf.Serializer.Deserialize>(ms);
        }
    }
}

2 votes

G'day Marc, j'adore le travail sur les protocol-buffers que tu as fait et je sais que ce post a presque 5 ans mais le netserializer cité dans une réponse ici (Binoj) indique que ta mise en œuvre n'est pas la plus rapide. Est-ce une affirmation/publicité juste ou y a-t-il un compromis ? Merci

0 votes

Ok, je vois maintenant, la NetSerialization ne fonctionne que pour la même version alors que je recherche une Sérialisation Tolérante à la Version

1 votes

Toute personne pensant que cela est rapide doit fumer quelque chose, cela pourrait être assez rapide pour de nombreux cas, et cela pourrait être plus rapide que de nombreux autres sérialiseurs, mais est-ce réellement rapide, comparé à l'analyse manuelle? Mon dieu non.

35voto

Maxim Points 1903

Une comparaison complète entre différents formats faite par moi dans ce post- https://medium.com/@maximn/serialization-performance-comparison-xml-binary-json-p-ad737545d227

Juste un exemple du post- enter image description here

10 votes

Ce n'est pas de la vitesse. C'est de la lenteur. Il est dit "moins c'est mieux" dans l'article lié.

2 votes

@TimurNuriyasov, c'est le temps qu'il a fallu pour effectuer l'opération

2 votes

Vous dites que le binaire est le plus lent? Je ne pense pas! Je suppose qu'il se réfère correctement à la vitesse, pas au temps.

24voto

Jeremy Holovacs Points 6879

Ayant un intérêt pour cela, j'ai décidé de tester les méthodes suggérées avec le test "apples to apples" le plus proche que je pouvais. 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("Génération de {0} tableaux de données...", count);
            var arrays = new List();
            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("Données de test générées.");
            var stopWatch = new Stopwatch();

            Console.WriteLine("Test du BinarySerializer...");
            var binarySerializer = new BinarySerializer();
            var binarySerialized = new List();
            var binaryDeserialized = new List();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                binarySerialized.Add(binarySerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("BinaryFormatteur: La sérialisation a pris {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in binarySerialized)
            {
                binaryDeserialized.Add(binarySerializer.Deserialize(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("BinaryFormatteur: La désérialisation a pris {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            Console.WriteLine();
            Console.WriteLine("Test du sérialiseur ProtoBuf...");
            var protobufSerializer = new ProtoBufSerializer();
            var protobufSerialized = new List();
            var protobufDeserialized = new List();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                protobufSerialized.Add(protobufSerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("ProtoBuf: La sérialisation a pris {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in protobufSerialized)
            {
                protobufDeserialized.Add(protobufSerializer.Deserialize(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("ProtoBuf: La désérialisation a pris {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            Console.WriteLine();
            Console.WriteLine("Test du sérialiseur NetSerializer...");
            var netSerializerSerializer = new ProtoBufSerializer();
            var netSerializerSerialized = new List();
            var netSerializerDeserialized = new List();

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var array in arrays)
            {
                netSerializerSerialized.Add(netSerializerSerializer.Serialize(array));
            }
            stopWatch.Stop();
            Console.WriteLine("NetSerializer: La sérialisation a pris {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            stopWatch.Reset();
            stopWatch.Start();
            foreach (var serialized in netSerializerSerialized)
            {
                netSerializerDeserialized.Add(netSerializerSerializer.Deserialize(serialized));
            }
            stopWatch.Stop();
            Console.WriteLine("NetSerializer: La désérialisation a pris {0}ms.", stopWatch.Elapsed.TotalMilliseconds);

            Console.WriteLine("Appuyez sur n'importe quelle touche pour terminer.");
            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(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(byte[] serialized)
            {
                using (var stream = new MemoryStream(serialized))
                {
                    var result = ProtoBuf.Serializer.Deserialize(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(byte[] serialized)
            {
                return Serializer.Deserialize(serialized);
            }
        }
    }
}

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

Génération de 100000 tableaux de données...
Données de test générées.
Test du BinarySerializer...
BinaryFormatteur: La sérialisation a pris 336.8392ms.
BinaryFormatteur: La désérialisation a pris 208.7527ms.

Test du sérialiseur ProtoBuf...
ProtoBuf: La sérialisation a pris 2284.3827ms.
ProtoBuf: La désérialisation a pris 2201.8072ms.

Test du sérialiseur NetSerializer...
NetSerializer: La sérialisation a pris 2139.5424ms.
NetSerializer: La désérialisation a pris 2113.7296ms.
Appuyez sur n'importe quelle touche pour terminer.

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

Génération de 10000 tableaux de données...
Données de test générées.
Test du BinarySerializer...
BinaryFormatter: La sérialisation a pris 285.8356ms.
BinaryFormatter: La désérialisation a pris 206.0906ms.

Test du sérialiseur ProtoBuf...
ProtoBuf: La sérialisation a pris 10693.3848ms.
ProtoBuf: La désérialisation a pris 5988.5993ms.

Test du sérialiseur NetSerializer...
NetSerializer: La sérialisation a pris 9017.5785ms.
NetSerializer: La désérialisation a pris 5978.7203ms.
Appuyez sur n'importe quelle touche pour terminer.

Ma conclusion, par conséquent, est que : 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, au moins d'un ordre de grandeur.

YMMV.

1 votes

Peut-être que BinaryFormatter est simplement très rapide avec les tableaux.

4 votes

Il est possible... mais dans les conditions mentionnées, les résultats étaient spectaculaires. La leçon ici pourrait bien être de ne pas croire qu'une méthode est la plus performante dans toutes les circonstances. Tester et comparer les performances éclaire toujours.

0 votes

En C++, la sérialisation d'objets est environ 100 fois plus rapide!

16voto

Pieter van Ginkel Points 17057

Protobuf est très très rapide.

Voir http://code.google.com/p/protobuf-net/wiki/Performance pour des informations approfondies concernant les performances de ce système et une mise en œuvre.

0 votes

Y a-t-il des inconvénients à utiliser Protobuf ?

11 votes

Vous devez annoter vos objets. Protobuf ne stocke pas les noms et types de champ comme le font les sérialiseurs, mais les récupère à 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. J'utilise cela 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 solution à privilégier.

0 votes

Avez-vous un exemple de code source complet utilisant Protobuf en C# à ajouter à la réponse?

15voto

Binoj Antony Points 7519

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

Les données fournies sur leur site montrent des performances de 2x - 4x supérieures à celles de protobuf, je ne l'ai pas testé moi-même, mais si vous évaluez différentes options, essayez celui-ci aussi

3 votes

Je viens d'essayer NetSerializer dans mon application et ça fonctionne à merveille. Ça vaut la peine d'essayer.

0 votes

Netserializer n'est pas adapté pour la sérialisation des objets "utilisateur" où la bibliothèque ne sait pas quels sont les types au départ, ou même n'a pas la possibilité de forcer l'utilisateur à marquer ses objets comme sérialisables.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X