web-dev-qa-db-fra.com

Sérialisation d'objets rapide et compacte dans .NET

Je souhaite utiliser la sérialisation d'objets pour communiquer sur le réseau entre un serveur Mono et les clients Silverlight. Il est assez important que la sérialisation soit économe en espace et assez rapide, car le serveur va héberger plusieurs jeux en temps réel.

Quelle technique dois-je utiliser? Le BinaryFormatter ajoute beaucoup de surcharge aux classes sérialisées (version, culture, nom de classe, noms de propriété, etc.) qui ne sont pas requises dans cette application.

Que puis-je faire pour rendre cet espace plus efficace?

57
Dennis Kempin

Vous pouvez utiliser Tampons de protocole . Je change tout mon code de sérialisation de BinaryFormatter avec compression en Protocol Buffers et j'obtiens de très bons résultats. Il est plus efficace à la fois dans le temps et dans l'espace.

Il existe deux implémentations .NET par Jon Skeet et Marc Gravell .

Mise à jour : L'implémentation officielle de .NET peut être trouvée ici .

68

J'ai quelques repères pour les sérialiseurs .NET de premier plan disponibles basés sur le jeu de données Northwind.

Northwind .NET serialization benchmarks

@marcgravell binaire protobuf-net est l'implémentation la plus rapide comparée, soit environ 7x plus rapide que le sérialiseur Microsoft le plus rapide disponible (XML DataContractSerializer) dans la BCL.

Je gère également des sérialiseurs de texte .NET open source à hautes performances:

  • JSV TypeSerializer un format compact, propre, de type JSON + CSV qui est 3,1 fois plus rapide que le DataContractSerializer
  • ainsi qu'un JsonSerializer c'est 2,6x plus rapide.
52
mythz

En tant qu'auteur, je vous invite à essayer protobuf-net ; il est livré avec des binaires pour Mono 2.0 et Silverlight 2.0, et est rapide et efficace . Si vous avez des problèmes, envoyez-moi un e-mail (voir mon profil Stack Overflow); le support est gratuit.

La version de Jon (voir la réponse acceptée précédemment) est également très bonne, mais IMO la version protobuf-net est plus idiomatique pour C # - Jon serait idéale si vous parliez de C # à Java, donc vous pourriez avoir une API similaire aux deux extrémités.

28
Marc Gravell

J'ai eu un problème similaire, bien que j'utilise simplement .NET. Je voulais envoyer des données sur Internet aussi rapidement et facilement que possible. Je n'ai rien trouvé qui soit suffisamment optimisé, j'ai donc créé mon propre sérialiseur, nommé NetSerializer .

NetSerializer a ses limites, mais elles n'ont pas affecté mon cas d'utilisation. Et je n'ai pas fait de repères depuis un moment, mais c'était beaucoup plus rapide que tout ce que j'ai trouvé.

Je ne l'ai pas essayé sur Mono ou Silverlight. Je parie que cela fonctionne sur Mono, mais je ne sais pas quel est le niveau de support pour DynamicMethods sur Silverlight.

8
Tomba

Vous pouvez essayer d'utiliser JSON. Ce n'est pas aussi efficace en bande passante que les tampons de protocole, mais il serait beaucoup plus facile de surveiller les messages avec des outils comme Wireshark, ce qui aide beaucoup lors du débogage de problèmes. .NET 3.5 est livré avec un sérialiseur JSON.

5
Pablote

Vous pouvez transmettre les données via un DeflateStream ou GZipStream pour les compresser avant la transmission. Ces classes vivent dans l'espace de noms System.IO.Compression.

4
Sean

J'ai eu un problème très similaire - l'enregistrement dans un fichier. Mais ce qui suit peut également être utilisé sur un réseau car il a été conçu pour la communication à distance.

La solution consiste à utiliser la bibliothèque de Simon Hewitt - voir Optimisation de la sérialisation dans .NET - partie 2.

Partie 1 de l'article déclare (le gras est mon accent): "... Si vous avez déjà utilisé la communication à distance .NET pour de grandes quantités de données, vous aurez constaté qu'il y a des problèmes d'évolutivité . Pour de petites quantités de données, cela fonctionne assez bien, mais de plus grandes quantités prennent beaucoup de CPU et de mémoire, génèrent des quantités massives de données pour la transmission , et peut échouer avec des exceptions de mémoire insuffisante. Il y a également un gros problème avec le temps nécessaire pour effectuer réellement la sérialisation - de grandes quantités de données peuvent rendre leur utilisation dans les applications impossible. "

J'ai obtenu un résultat similaire pour mon application particulière, une économie 40 fois plus rapide et un chargement 20 fois plus rapide (de quelques minutes à quelques secondes). La taille des données sérialisées a également été considérablement réduite. Je ne me souviens pas exactement, mais c'était au moins 2-3 fois.

Il est assez facile de commencer. Cependant, il y a un problème: n'utilisez la sérialisation .NET que pour la structure de données de niveau le plus élevé (pour démarrer la sérialisation/désérialisation), puis appelez les fonctions de sérialisation/désérialisation directement pour les champs de la structure de données de niveau le plus élevé. Sinon, il n'y aura pas d'accélération ... Par exemple, si une structure de données particulière (disons Generic.List) n'est pas pris en charge par la bibliothèque, alors la sérialisation .NET sera utilisée à la place et c'est un non-non. Au lieu de cela, sérialisez la liste en code client (ou similaire). Pour un exemple, voir près de "'Ceci est notre propre encodage." dans la même fonction que celle indiquée ci-dessous.

Pour référence: code de mon application - voir près de "Remarque: c'est le seul endroit où nous utilisons le .NET intégré ...".

3
Peter Mortensen

Vous pouvez essayer BOIS qui se concentre sur la taille des données compressées et fournit le meilleur emballage à ce jour. (Je n'ai pas encore vu une meilleure optimisation.)

https://github.com/salarcode/Bois

2
Salar