2009-11-04 3 views
13

Un tableau BinaryFormatter-sérialisée de 128³ doubles, prend 50 Mo d'espace. La sérialisation d'un réseau de 128³ struct s avec deux doubles champs occupe 150 Mo et plus de 20 secondes à traiter.alternatives BinaryFormatter

Y at-il des solutions de rechange simple et rapide qui généreraient des fichiers compacts? Mon attente est que les exemples ci-dessus prendraient 16 et 32 ​​Mo, respectivement, et moins de deux secondes à traiter. J'ai jeté un oeil à protobuf-net, mais il semble qu'il ne supporte même pas struct tableaux.

PS: Je suis désolé de faire une erreur dans l'enregistrement de la taille des fichiers. L'espace disque réel avec BinaryFormatter n'est pas important.

Répondre

4

Sérialisation signifie que les métadonnées sont ajoutées afin que les données peuvent être en toute sécurité désérialisé, c'est ce qui cause la surcharge. Si vous sérialiser les données vous-même sans métadonnées, vous vous retrouvez avec 16 Mo de données:

foreach (double d in array) { 
    byte[] bin = BitConverter.GetBytes(d); 
    stream.Write(bin, 0, bin.Length); 
} 

Cela signifie bien sûr que vous devez désérialiser les données vous-même aussi:

using (BinaryReader reader = new BinaryReader(stream)) { 
    for (int i = 0; i < array.Length; i++) { 
     byte[] data = reader.ReadBytes(8); 
     array[i] = BitConverter.ToDouble(data, 0); 
    } 
} 
7

Si vous utilisez un BinaryWriter au lieu d'un Serializer vous obtiendrez la taille désirée (mimimal).
Je ne suis pas sûr de la vitesse, mais essayez-le.

Sur mon 32Mo d'écriture du système prend moins de 0,5 seconde, y compris ouverture et de fermeture du flux.

Vous devrez écrire vos propres pour boucles d'écrire les données, comme ceci:

struct Pair 
{ 
    public double X, Y; 
} 

static void WritePairs(string filename, Pair[] data) 
{ 
    using (var fs = System.IO.File.Create(filename)) 
    using (var bw = new System.IO.BinaryWriter(fs)) 
    { 
     for (int i = 0; i < data.Length; i++) 
     { 
      bw.Write(data[i].X); 
      bw.Write(data[i].Y); 
     } 
    } 
} 

static void ReadPairs(string fileName, Pair[] data) 
{ 
    using (var fs = System.IO.File.OpenRead(fileName)) 
    using (var br = new System.IO.BinaryReader(fs)) 
    { 
     for (int i = 0; i < data.Length; i++) 
     { 
      data[i].X = br.ReadDouble(); 
      data[i].Y = br.ReadDouble(); 
     } 
    } 
} 
+2

sérialisation manuel peut en effet être très rapide et compact, mais il est aussi sujette à l'erreur et de temps à écrire. Je m'attends à des frais généraux, mais avec BinaryFormatter c'est souvent déraisonnable. –

+0

Vous pouvez le rendre un peu plus convivial avec des génériques et/ou des interfaces. Mais commencez à ajouter des méta et vous approcherez rapidement des frais généraux des formateurs. –

+0

Spot sur Henk. BinaryFormatter fonctionnera avec à peu près * n'importe quoi *. Vous devriez vous attendre à une meilleure performance de quelque chose exactement ce dont vous avez besoin et * seulement * ce dont vous avez besoin. –

2

Ceci est plus d'un commentaire, mais il est beaucoup trop pour une seule ... Je ne suis pas capable de reproduire vos résultats. Il y a cependant un surcoût supplémentaire avec la structure.

Mes tests:

------------------------------------------------------------------------------- 
Testing array of structs 

Size of double: 8 
Size of doubles.bin: 16777244 
Size per array item: 8 
Milliseconds to serialize: 143 
------------------------------------------------------------------------------- 
------------------------------------------------------------------------------- 
Testing array of structs 

Size of dd struct: 16 
Size of structs.bin: 52428991 
Size per array item: 25 
Milliseconds to serialize: 9678 
------------------------------------------------------------------------------- 

code:

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

namespace ConsoleApplication5 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      TestDoubleArray(); 
      TestStructArray(); 
     } 

     private static void TestStructArray() 
     { 

      Stopwatch stopWatch = new Stopwatch(); 
      stopWatch.Start(); 

      dd[] d1 = new dd[2097152]; 
      BinaryFormatter f1 = new BinaryFormatter(); 
      f1.Serialize(File.Create("structs.bin"), d1); 

      stopWatch.Stop(); 

      Debug.WriteLine("-------------------------------------------------------------------------------"); 
      Debug.WriteLine("Testing array of structs"); 
      Debug.WriteLine(""); 
      Debug.WriteLine("Size of dd struct: " + System.Runtime.InteropServices.Marshal.SizeOf(typeof(dd)).ToString()); 
      FileInfo fi = new FileInfo("structs.bin"); 
      Debug.WriteLine("Size of structs.bin: " + fi.Length.ToString()); 
      Debug.WriteLine("Size per array item: " + (fi.Length/2097152).ToString()); 
      Debug.WriteLine("Milliseconds to serialize: " + stopWatch.ElapsedMilliseconds); 
      Debug.WriteLine("-------------------------------------------------------------------------------"); 
     } 

     static void TestDoubleArray() 
     { 
      Stopwatch stopWatch = new Stopwatch(); 
      stopWatch.Start(); 

      double[] d = new double[2097152]; 
      BinaryFormatter f = new BinaryFormatter(); 
      f.Serialize(File.Create("doubles.bin"), d); 

      stopWatch.Stop(); 

      Debug.WriteLine("-------------------------------------------------------------------------------"); 
      Debug.WriteLine("Testing array of structs"); 
      Debug.WriteLine(""); 
      Debug.WriteLine("Size of double: " + sizeof(double).ToString()); 
      FileInfo fi = new FileInfo("test.bin"); 
      Debug.WriteLine("Size of doubles.bin: " + fi.Length.ToString()); 
      Debug.WriteLine("Size per array item: " + (fi.Length/2097152).ToString()); 
      Debug.WriteLine("Milliseconds to serialize: " + stopWatch.ElapsedMilliseconds); 
      Debug.WriteLine("-------------------------------------------------------------------------------"); 
     } 

     [Serializable] 
     struct dd 
     { 
      double a; 
      double b; 
     } 
    } 
} 
+0

Merci pour la correction. Ma faute. L'espace disponible n'est pas très grand. Le temps que prend le sérialiseur reste cependant très important. –

+0

Comme je l'ai commenté sur le post de Henk, vous traitez la généralisation et la standardisation (BinaryFormatter) pour la vitesse d'une classe spécialisée en faisant sa seule tâche ** très bien **. –

+0

Il me semble que je cours beaucoup trop vite - un ordre de grandeur au-delà d'un montant raisonnable. Il n'est pas nécessaire de prendre autant de temps pour générer le code dans la réponse de Henk Holterman. –