2009-11-04 8 views
13

BinaryFormatter-сериализованный массив из 128 точек на дюйм, занимает 50 МБ пространства. Сериализация массива из 1283 struct s с двумя double поля занимают 150 МБ и более 20 секунд для обработки.Альтернативы BinaryFormatter

Существуют ли быстрые простые альтернативы, которые генерируют компактные файлы? Мое предположение заключается в том, что приведенные выше примеры занимают соответственно 16 и 32 Мбайт, а для обработки - менее двух секунд. Я взглянул на protobuf-net, но кажется, что он даже не поддерживает struct массивов.

PS: Извиняюсь за ошибку при записи файлов. Фактические пробелы с BinaryFormatter невелики.

ответ

4

Сериализация означает, что метаданные добавляются так, что данные можно безопасно десериализовать, вот что вызывает накладные расходы. Если вы сериализации к представлению данных самостоятельно, без каких-либо метаданных, вы в конечном итоге с 16 МБ данных:

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

Это, конечно, означает, что вы должны десериализации данные сами также:

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

Если вы используете BinaryWriter вместо Serializer вы получите желаемый (минимальный) размер.
Я не уверен в скорости, но дайте ему попробовать.

На моей системной записи 32 МБ занимает менее 0,5 секунды, включая «Открыть» и «Закрыть поток».

Вам придется написать свою собственную для петли для записи данных, как это:

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

Руководство сериализации действительно может быть очень быстрым и компактным, но он также подвержен ошибкам и отнимает много времени, чтобы писать. Я ожидаю некоторые накладные расходы, но с BinaryFormatter часто необоснованно. –

+0

Вы можете сделать его немного более дружелюбным с дженериками и/или интерфейсами. Но начните добавлять мета, и вы быстро приблизитесь к накладным расходам Formatters. –

+0

Пятно на Хенк. BinaryFormatter будет работать примерно с * ничего *. Вы должны ожидать, что лучшая производительность от чего-то делает именно то, что вам нужно, и * только * то, что вам нужно. –

2

Это больше комментария, но это слишком много для одного ... Я не способный воспроизводить ваши результаты. Тем не менее, есть некоторые дополнительные накладные расходы со структурой.

Мои испытания:

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

Код:

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

Благодарим вас за исправление. Виноват. Накладные расходы не очень большие. Тем не менее, время, затрачиваемое на сериализатор, по-прежнему очень важно. –

+0

Как я прокомментировал сообщение Хенка, вы торгуете обобщением и стандартизацией (BinaryFormatter) для скорости специализированного класса, выполняющего одну задачу ** очень хорошо **. –

+0

Похоже, я торгую слишком большой скоростью - на порядок выше разумной суммы. Не нужно так долго генерировать код в ответе Хенка Холтермана. –