2012-03-30 86 views
11

我對僅由結構構成的簡單對象結構表示的地理數據有着巨大的興趣。我所有的領域都是有價值的。結構的快速序列化/反序列化

public struct Child 
{ 
    readonly float X; 
    readonly float Y; 
    readonly int myField; 
} 

public struct Parent 
{ 
    readonly int id; 
    readonly int field1; 
    readonly int field2; 
    readonly Child[] children; 
} 

的數據被分塊很好地最多的Parent[] -s一小部分。每個數組包含幾千個父實例。我有太多的數據來保存所有的內存,所以我需要來回交換這些塊到磁盤。 (一個文件將導致約2-300KB)。

將dumpint序列化或反序列化爲爲byte[]以將dumpint轉儲到磁盤並讀回的最有效方式是什麼?關於速度,我對快速反序列化特別感興趣,寫入速度並不那麼關鍵。

簡單BinarySerializer夠好嗎? 或者我應該用StructLayout (see accepted answer)破解?我不確定這是否會與Parent.children的數組字段一起工作。

更新:對評論的迴應 - 是的,對象是不可變的(代碼更新),而且children字段不是值類型。 300KB聽起來不怎麼樣,但我有很多這樣的文件,所以速度很重要。

+4

_我的所有字段的值都是type_ - 「children」字段不是值類型。 – 2012-03-30 14:46:04

+1

300KB爲小數量,這個數量在0.1s無反轉優化中被反序列化/序列化 – 2012-03-30 14:47:21

+0

是否所有數據都是隻讀的? – usr 2012-03-30 14:52:13

回答

10

BinarySerializer是一個非常通用的序列化程序。它的性能不如自定義實現。

幸運的是,您的數據僅包含結構。這意味着您將能夠修復Child的structlayout,並使用從磁盤讀取的byte []中的不安全代碼對子數組進行位複製。

對於父母來說並不那麼容易,因爲你需要分開對待孩子。我建議您使用不安全的代碼從您讀取的字節[]中複製可複製字段,並分別反序列化子代。

您是否考慮過使用內存映射文件將所有孩子映射到內存中?然後,您可以重新使用操作系統緩存工具,而不必處理讀寫操作。

零拷貝反序列化兒童[]這個樣子的:

byte[] bytes = GetFromDisk(); 
fixed (byte* bytePtr = bytes) { 
Child* childPtr = (Child*)bytePtr; 
//now treat the childPtr as an array: 
var x123 = childPtr[123].X; 

//if we need a real array that can be passed around, we need to copy: 
var childArray = new Child[GetLengthOfDeserializedData()]; 
for (i = [0..length]) { 
    childArray[i] = childPtr[i]; 
} 
} 
+0

我查了內存映射文件,他們看起來很棒的磁盤訪問管理!你能寫一個不安全的細分市場的例子嗎?如何在不安全模式下將一個字節[]轉換爲子[]?因爲如你所說,這將需要零時間。 – user256890 2012-03-30 17:38:38

+1

我添加了一個例子。如果你想零拷貝,你需要改變你的應用使用指針或不安全的IO使用ReadFile(直接讀入一個現有的Child [])。但我的猜測是,複製的一次傳遞真的沒有。 CPU很擅長。 – usr 2012-03-30 17:48:51

10

如果你不喜歡下去的寫你自己的序列路線,你可以使用protobuf.net串行器。下面是一個小的測試程序的輸出:

Using 3000 parents, each with 5 children 
BinaryFormatter Serialized in: 00:00:00.1250000 
Memory stream 486218 B 
BinaryFormatter Deserialized in: 00:00:00.1718750 

ProfoBuf Serialized in: 00:00:00.1406250 
Memory stream 318247 B 
ProfoBuf Deserialized in: 00:00:00.0312500 

它應該是相當不言自明。這只是一次運行,但相當顯示了我看到的速度(3-5x)。

爲了讓你的結構可序列化(使用protobuf。網),只需添加如下屬性:

[ProtoContract] 
[Serializable] 
public struct Child 
{ 
    [ProtoMember(1)] public float X; 
    [ProtoMember(2)] public float Y; 
    [ProtoMember(3)] public int myField; 
} 

[ProtoContract] 
[Serializable] 
public struct Parent 
{ 
    [ProtoMember(1)] public int id; 
    [ProtoMember(2)] public int field1; 
    [ProtoMember(3)] public int field2; 
    [ProtoMember(4)] public Child[] children; 
} 

UPDATE:

其實,寫一個自定義序列化是很容易的,這裏是一個最基本的實現:

class CustSerializer 
{ 
    public void Serialize(Stream stream, Parent[] parents, int childCount) 
    { 
     BinaryWriter sw = new BinaryWriter(stream); 
     foreach (var parent in parents) 
     { 
      sw.Write(parent.id); 
      sw.Write(parent.field1); 
      sw.Write(parent.field2); 

      foreach (var child in parent.children) 
      { 
       sw.Write(child.myField); 
       sw.Write(child.X); 
       sw.Write(child.Y); 
      } 
     } 
    } 

    public Parent[] Deserialize(Stream stream, int parentCount, int childCount) 
    { 
     BinaryReader br = new BinaryReader(stream); 
     Parent[] parents = new Parent[parentCount]; 

     for (int i = 0; i < parentCount; i++) 
     { 
      var parent = new Parent(); 
      parent.id = br.ReadInt32(); 
      parent.field1 = br.ReadInt32(); 
      parent.field2 = br.ReadInt32(); 
      parent.children = new Child[childCount]; 

      for (int j = 0; j < childCount; j++) 
      { 
       var child = new Child(); 
       child.myField = br.ReadInt32(); 
       child.X = br.ReadSingle(); 
       child.Y = br.ReadSingle(); 
       parent.children[j] = child; 
      } 

      parents[i] = parent; 
     } 
     return parents; 
    } 
} 

這裏是其輸出在簡單的速度測試中運行時:

Custom Serialized in: 00:00:00 
Memory stream 216000 B 
Custom Deserialized in: 00:00:00.0156250 

很顯然,它比其他方法靈活性低很多,但如果速度真的如此重要,它的速度比protobuf方法快2-3倍。它也產生最小的文件大小,因此寫入磁盤應該更快。

+1

在大多數情況下,Protobuf在易用性和性能之間是一個很好的折衷。如果你想堅持下去,它仍然無法擊敗定製解決方案的性能。特別是一個可以精確到零的成本! – usr 2012-03-30 17:02:01