2012-03-30 17 views
11

मेरे पास भौतिक डेटा का विशाल हिस्सा है जो साधारण ऑब्जेक्ट संरचना में दर्शाया गया है जिसमें केवल structs शामिल हैं। मेरे सभी फ़ील्ड मूल्य प्रकार के हैं।फास्ट सीरियलाइजेशन/structs के deserialization

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 के छोटे हिस्से को अच्छी तरह से ऊपर chunked है। प्रत्येक सरणी में कुछ हज़ारों अभिभावक उदाहरण होते हैं। मेरे पास स्मृति में सभी को रखने के लिए बहुत अधिक डेटा है, इसलिए मुझे इन हिस्सों को डिस्क पर आगे और पीछे स्वैप करने की आवश्यकता है। (एक फ़ाइल लगभग 2-300 केबी का परिणाम होगा)।

Parent[] को byte[] पर डिस्क पर डंपिंट और डिस्क पढ़ने के लिए क्रमबद्ध करने/deserializing का सबसे प्रभावी तरीका क्या होगा? गति के बारे में, मुझे विशेष रूप से तेजी से deserialization में रुचि है, लिखना गति महत्वपूर्ण नहीं है।

आसान BinarySerializer पर्याप्त होगा? या मुझे StructLayout (see accepted answer) के साथ चारों ओर हैक करना चाहिए? मुझे यकीन नहीं है कि क्या यह Parent.children के सरणी क्षेत्र के साथ काम करेगा।

अद्यतन: टिप्पणियों पर प्रतिक्रिया - हां, वस्तुएं अपरिवर्तनीय (कोड अपडेट की गई हैं) और वास्तव में children फ़ील्ड मान प्रकार नहीं है। 300 केबी बहुत ज्यादा नहीं लगता है लेकिन मेरे पास इस तरह की फाइलें हैं, इसलिए गति मायने रखती है।

+4

_ मेरे सभी फ़ील्ड मान प्रकार_ हैं- 'बच्चों का फ़ील्ड एक मान प्रकार नहीं है। –

+1

300 केबी छोटी राशि है, यह राशि 0.1s w/o अनुकूलन –

+0

में deserialized/serialized है क्या आपका सभी डेटा केवल पढ़ने के लिए है? – usr

उत्तर

10

बाइनरीसेरियलाइज़र एक बहुत ही सामान्य धारावाहिक है। यह एक कस्टम कार्यान्वयन के साथ ही प्रदर्शन नहीं करेगा।

सौभाग्य से आपके डेटा में केवल structs होते हैं। इसका मतलब है कि आप चाइल्ड के लिए स्ट्रक्चरआउट को ठीक करने में सक्षम होंगे और डिस्क से पढ़े गए बाइट [] से असुरक्षित कोड का उपयोग करके बच्चों की सरणी को बिट-कॉपी करें।

माता-पिता के लिए यह इतना आसान नहीं है क्योंकि आपको बच्चों को अलग से इलाज करने की आवश्यकता है। मैं आपको बाइट से बिट-कॉपी करने योग्य फ़ील्ड की प्रतिलिपि बनाने के लिए असुरक्षित कोड का उपयोग करने की सलाह देता हूं [] आप बच्चों को अलग-अलग पढ़ते और deserialize।

क्या आपने मेमोरी मैप की गई फ़ाइलों का उपयोग करके सभी बच्चों को मेमोरी में मैप करने पर विचार किया था? फिर आप ऑपरेटिंग सिस्टम कैश सुविधा का फिर से उपयोग कर सकते हैं और पढ़ने और लिखने के साथ सौदा नहीं कर सकते हैं।

शून्य-प्रतिलिपि-deserializing एक बच्चे [] इस तरह दिखता है:

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

+1

मैंने एक उदाहरण जोड़ा। यदि आप शून्य प्रतिलिपि चाहते हैं तो आपको रीडफाइल का उपयोग करके पॉइंटर्स या असुरक्षित IO का उपयोग करने के लिए अपने ऐप को बदलने की आवश्यकता है (सीधे एक मौजूदा बच्चे [] में पढ़ें)। लेकिन मेरा अनुमान है कि प्रतिलिपि का एक ही पास वास्तव में कुछ भी नहीं है। सीपीयू उस पर अच्छे हैं। – usr

10

आप कल्पना नीचे जा रहा नहीं है, तो अपनी खुद की serializer मार्ग लिखते हैं, आप protobuf.net serializer उपयोग कर सकते हैं। यहाँ एक छोटे से परीक्षण कार्यक्रम से उत्पादन है:

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) की काफी संकेतक था।

अपने structs serializable (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; 
} 

अद्यतन:

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

यहाँ और है:

वास्तव में, एक कस्टम serializer लिख रहा है बहुत आसान है, यहाँ एक नंगे हड्डियों कार्यान्वयन है इसके उत्पादन जब एक साधारण गति परीक्षण में चलाएँ:

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

जाहिर है, यह अन्य दृष्टिकोणों की तुलना में बहुत कम लचीला है, लेकिन यदि गति वास्तव में महत्वपूर्ण है तो यह प्रोटोबफ विधि से 2-3x तेज है। यह न्यूनतम फ़ाइल आकार भी बनाता है, इसलिए डिस्क पर लिखना तेज होना चाहिए।

+1

अधिकांश मामलों में उपयोग और प्रदर्शन की आसानी के बीच प्रोटोबफ एक महान व्यापार-बंद है। यदि आप पागल जाना चाहते हैं तो यह अभी भी एक कस्टम समाधान के प्रदर्शन को हरा नहीं सकता है। विशेष रूप से एक बिट-ब्लिटेबल जिसे वास्तव में शून्य की लागत हो सकती है! – usr

संबंधित मुद्दे