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.
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.0 votes
D'accord, je comprends, je voulais dire en termes de performance...
0 votes
Il y a de nombreux liens là-bas. Un tel lien : blogs.msdn.com/b/youssefm/archive/2009/07/10/…
0 votes
Vitesse est un aspect, la taille produite en est un autre, la sécurité en est un troisième. Les sérialiseurs sécurisés sont généralement non polymorphes et peuvent nécessiter des contrats annotés. Mais la vitesse de la sérialisation en elle-même est négligeable de toute façon, si la charge utile est extraite d'un flux réseau, d'un fichier ou d'une base de données. Je ne vais pas copier-coller une réponse précédente ici alors consultez le lien pour plus de réflexions sur les sérialiseurs binaires (et polymorphes).