2010-01-29 15 views
9

मेरे पास 2 सीएसवी फाइलों की तुलना करने के लिए एक उपकरण है और फिर प्रत्येक सेल को 6 बाल्टी में से एक में बाल्टी करें। असल में, यह सीएसवी फाइलों में पढ़ता है (तेज़ सीएसवी रीडर, क्रेडिट: http://www.codeproject.com/KB/database/CsvReader.aspx का उपयोग करके) और उसके बाद उपयोगकर्ता द्वारा प्रदान की गई कुंजियों के आधार पर प्रत्येक फ़ाइल से संबंधित एक शब्दकोश बनाता है। मैं फिर मूल्यों की तुलना में और परिणाम सीएसवी फ़ाइल लिखने के माध्यम से वें शब्दकोशों के माध्यम से पुनरावृत्त करता हूं।सी # शब्दकोश और कुशल मेमोरी उपयोग

हालांकि यह तेजी से चमक रहा है, यह स्मृति उपयोग के मामले में बहुत अक्षम है। मैं 3 जीबी भौतिक मेमोरी के साथ अपने बॉक्स पर 150 एमबी से अधिक फाइलों की तुलना नहीं कर सकता।

अपेक्षित फ़ाइल को पढ़ने के लिए यहां एक कोड स्निपेट है। इस टुकड़े के अंत में, मेमोरी उपयोग टास्क मैनेजर से 500 एमबी के करीब है।

// Read Expected 
long rowNumExp; 
System.IO.StreamReader readerStreamExp = new System.IO.StreamReader(@expFile); 
SortedDictionary<string, string[]> dictExp = new SortedDictionary<string, string[]>(); 
List<string[]> listDupExp = new List<string[]>(); 
using (CsvReader readerCSVExp = new CsvReader(readerStreamExp, hasHeaders, 4096)) 
{ 
    readerCSVExp.SkipEmptyLines = false; 
    readerCSVExp.DefaultParseErrorAction = ParseErrorAction.ThrowException; 
    readerCSVExp.MissingFieldAction = MissingFieldAction.ParseError; 
    fieldCountExp = readerCSVExp.FieldCount;     
    string keyExp; 
    string[] rowExp = null; 
    while (readerCSVExp.ReadNextRecord()) 
    { 
     if (hasHeaders == true) 
     { 
      rowNumExp = readerCSVExp.CurrentRecordIndex + 2; 
     } 
     else 
     { 
      rowNumExp = readerCSVExp.CurrentRecordIndex + 1; 
     } 
     try 
     { 
      rowExp = new string[fieldCount + 1];      
     } 
     catch (Exception exExpOutOfMemory) 
     { 
      MessageBox.Show(exExpOutOfMemory.Message); 
      Environment.Exit(1); 
     }     
     keyExp = readerCSVExp[keyColumns[0] - 1]; 
     for (int i = 1; i < keyColumns.Length; i++) 
     { 
      keyExp = keyExp + "|" + readerCSVExp[i - 1]; 
     } 
     try 
     { 
      readerCSVExp.CopyCurrentRecordTo(rowExp); 
     } 
     catch (Exception exExpCSVOutOfMemory) 
     { 
      MessageBox.Show(exExpCSVOutOfMemory.Message); 
      Environment.Exit(1); 
     } 
     try 
     { 
      rowExp[fieldCount] = rowNumExp.ToString(); 
     } 
     catch (Exception exExpRowNumOutOfMemory) 
     { 
      MessageBox.Show(exExpRowNumOutOfMemory.Message); 
      Environment.Exit(1); 
     } 
     // Dedup Expected       
     if (!(dictExp.ContainsKey(keyExp))) 
     { 
      dictExp.Add(keyExp, rowExp);       
     } 
     else 
     { 
      listDupExp.Add(rowExp); 
     }      
    }     
    logFile.WriteLine("Done Reading Expected File at " + DateTime.Now); 
    Console.WriteLine("Done Reading Expected File at " + DateTime.Now + "\r\n"); 
    logFile.WriteLine("Done Creating Expected Dictionary at " + DateTime.Now); 
    logFile.WriteLine("Done Identifying Expected Duplicates at " + DateTime.Now + "\r\n");     
} 

क्या कुछ भी है, मैं इसे और अधिक मेमोरी कुशल बनाने के लिए कर सकता हूं? कम मैर्मरी का उपभोग करने के लिए मैं कुछ भी अलग कर सकता था?

किसी भी विचार का स्वागत है।

सभी प्रतिक्रियाओं के लिए धन्यवाद दोस्तों।

मैंने शब्दकोशों में पंक्ति के बजाय पंक्ति की अनुक्रमणिका को स्टोर करने के लिए सुझाए गए परिवर्तनों को शामिल किया है।

नए कार्यान्वयन के साथ एक ही कोड खंड है।

// Read Expected 
     long rowNumExp; 
     SortedDictionary<string, long> dictExp = new SortedDictionary<string, long>(); 
     System.Text.StringBuilder keyExp = new System.Text.StringBuilder(); 
     while (readerCSVExp.ReadNextRecord()) 
     { 
      if (hasHeaders == true) 
      { 
       rowNumExp = readerCSVExp.CurrentRecordIndex + 2; 
      } 
      else 
      { 
       rowNumExp = readerCSVExp.CurrentRecordIndex + 1; 
      } 
      for (int i = 0; i < keyColumns.Length - 1; i++) 
      { 
       keyExp.Append(readerCSVExp[keyColumns[i] - 1]); 
       keyExp.Append("|"); 
      } 
      keyExp.Append(readerCSVExp[keyColumns[keyColumns.Length - 1] - 1]); 
      // Dedup Expected      
      if (!(dictExp.ContainsKey(keyExp.ToString()))) 
      { 
       dictExp.Add(keyExp.ToString(), rowNumExp); 
      } 
      else 
      { 
       // Process Expected Duplicates   
       string dupExp; 
       for (int i = 0; i < fieldCount; i++) 
       { 
        if (i >= fieldCountExp) 
        { 
         dupExp = null; 
        } 
        else 
        { 
         dupExp = readerCSVExp[i]; 
        } 
        foreach (int keyColumn in keyColumns) 
        { 
         if (i == keyColumn - 1) 
         { 
          resultCell = "duplicateEXP: '" + dupExp + "'"; 
          resultCell = CreateCSVField(resultCell); 
          resultsFile.Write(resultCell); 
          comSumCol = comSumCol + 1; 
          countDuplicateExp = countDuplicateExp + 1; 
         } 
         else 
         { 
          if (checkPTColumns(i + 1, passthroughColumns) == false) 
          { 
           resultCell = "'" + dupExp + "'"; 
           resultCell = CreateCSVField(resultCell); 
           resultsFile.Write(resultCell); 
           countDuplicateExp = countDuplicateExp + 1; 
          } 
          else 
          { 
           resultCell = "PASSTHROUGH duplicateEXP: '" + dupExp + "'"; 
           resultCell = CreateCSVField(resultCell); 
           resultsFile.Write(resultCell); 
          } 
          comSumCol = comSumCol + 1; 
         } 
        } 
        if (comSumCol <= fieldCount) 
        { 
         resultsFile.Write(csComma); 
        } 
       } 
       if (comSumCol == fieldCount + 1) 
       { 
        resultsFile.Write(csComma + rowNumExp); 
        comSumCol = comSumCol + 1; 
       } 
       if (comSumCol == fieldCount + 2) 
       { 
        resultsFile.Write(csComma); 
        comSumCol = comSumCol + 1; 
       } 
       if (comSumCol > fieldCount + 2) 
       { 
        comSumRow = comSumRow + 1; 
        resultsFile.Write(csCrLf); 
        comSumCol = 1; 
       } 
      } 
      keyExp.Clear(); 
     } 
     logFile.WriteLine("Done Reading Expected File at " + DateTime.Now + "\r\n"); 
     Console.WriteLine("Done Reading Expected File at " + DateTime.Now + "\r\n"); 
     logFile.WriteLine("Done Analyzing Expected Duplicates at " + DateTime.Now + "\r\n"); 
     Console.WriteLine("Done Analyzing Expected Duplicates at " + DateTime.Now + "\r\n"); 
     logFile.Flush(); 

हालांकि, समस्या यह है कि मुझे स्मृति में डेटा सेट दोनों की आवश्यकता है। मैं वास्तव में कुंजी के आधार पर मिलान, मेलमिच, डुप्लिकेट और ड्रॉपआउट की तलाश करने वाले दोनों शब्दकोशों के माध्यम से पुन: प्रयास करता हूं।

पंक्ति अनुक्रमणिका को संग्रहीत करने के इस दृष्टिकोण का उपयोग करके, मैं अभी भी बहुत मेमोरी का उपयोग कर रहा हूं क्योंकि गतिशील पहुंच के लिए मुझे अब सीएसवी रीडर के कैश संस्करण का उपयोग करना है। तो हालांकि शब्दकोश अब बहुत छोटा है, डेटा की कैशिंग बचत के लिए तैयार होती है और मैं अभी भी इसी तरह के स्मृति उपयोग के साथ समाप्त हुआ।

आशा है, मैं के रूप में तेजी से अर्थ निकालने कर रहा हूँ ... :)

एक विकल्प 2 फ़ाइलों के माध्यम से पूरी तरह से और बस पाश शब्दकोश से छुटकारा पाने के लिए है, लेकिन यकीन नहीं करता है, तो प्रदर्शन किया जाएगा 2 की तुलना के रूप में शब्दकोशों।

किसी भी इनपुट की बहुत सराहना की जाती है।

+0

सीएसवी रीडर को कैश करने के बजाए, क्या आप फ़ाइल में रिकॉर्ड स्थानों को कैश नहीं कर सकते हैं, ताकि आप बाद में रिकॉर्ड प्राप्त कर सकें? जब आप कुंजीपटल के माध्यम से ड्रॉपआउट आदि की तलाश में शब्दकोशों के माध्यम से पुनरावृत्त करते हैं तो क्या आप वास्तविक डेटा या केवल चाबियाँ देख रहे हैं? –

+0

क्या आपने शब्दकोश में जाने से पहले स्ट्रिंग को इंटर्न करने का प्रयास किया था? क्या इससे कोई फर्क पड़ता है? क्या इनमें से किसी ने स्मृति उपयोग के साथ मदद की है? –

उत्तर

7

आप स्ट्रिंगबिल्डर द्वारा keyExp को प्रतिस्थापित कर सकते हैं। एक लूप में स्ट्रिंग को फिर से आवंटित करना, जैसे स्ट्रिंग्स अपरिवर्तनीय हैं, उतनी मेमोरी आवंटित रखेगी।

StringBuilder keyExp = new StringBuilder(); 
... 
    keyExp.Append("|" + readerCSVExp[i - 1]) ; 
... 

बहुत सारे तार समान हैं? आप interning them की कोशिश कर सकते, तो किसी भी समान तार प्रतियां होने से एक ही स्मृति बल्कि साझा करेंगे ...

rowExp[fieldCount] = String.Intern(rowNumExp.ToString()); 

// Dedup Expected    
string internedKey = (String.Intern(keyExp.ToString()));   
if (!(dictExp.ContainsKey(internedKey))) 
{ 
    dictExp.Add(internedKey, rowExp);       
} 
else 
{ 
    listDupExp.Add(rowExp); 
} 

मैं कुछ नहीं कर रहा हूँ वास्तव में कैसे कोड काम करता है लेकिन ... कि परे मैं तुम्हें कहेंगे डॉन शब्दकोश में rowExp रखने की आवश्यकता नहीं है, किसी और चीज को एक नंबर की तरह रखें और rowExp किसी अन्य फ़ाइल में डिस्क पर वापस लिखें। यह शायद आपको सबसे अधिक स्मृति बचाएगा क्योंकि यह फ़ाइल से तारों की एक सरणी प्रतीत होता है, इसलिए शायद बड़ा है। यदि आप इसे किसी फ़ाइल में लिखते हैं और फ़ाइल को उस नंबर में रखते हैं तो आप भविष्य में फिर से वापस आ सकते हैं यदि आपको प्रक्रिया करने की आवश्यकता है।यदि आपने फ़ाइल में ऑफसेट को शब्दकोश में मूल्य के रूप में सहेज लिया है, तो इसे फिर से ढूंढने में सक्षम हो। शायद :)।

+0

दिलचस्प, मैं सोच रहा था कि संकलक/दुभाषिया/जिटर/कुछ स्वचालित रूप से तारों को प्रशिक्षित करता है, लेकिन शायद यह केवल उन स्टिंग्स के लिए है जो मुझे लगता है कि संकलन समय में समान होने के लिए जाना जाता है। – Davy8

+0

@ डेवी 8, यह सही है। स्ट्रिंग इंटर्निंग केवल संकलन-समय स्थिरांक से बनाए गए तारों पर डिफ़ॉल्ट रूप से होती है। –

3

मुझे बताएं कि मुझे कुछ गलत है या नहीं।

उपरोक्त कोड एक CSV फ़ाइल पढ़ता है और डुप्लिकेट कुंजी की तलाश करता है। प्रत्येक पंक्ति दो सेटों में से एक में जाती है, डुप्लिकेट कुंजी के लिए, और बिना किसी के।

इन पंक्तियों के साथ आप क्या करते हैं?

क्या वे अलग-अलग फाइलों में लिखे गए हैं?

यदि ऐसा है तो सूची में गैर-अनक्यू पंक्तियों को स्टोर करने का कोई कारण नहीं है, क्योंकि आप उन्हें फ़ाइल में लिखते हैं।

जब आपको डुप्लिकेट मिलते हैं, तो पूरी पंक्ति को स्टोर करने की आवश्यकता नहीं होती है, केवल कुंजी संग्रहित करें, और फ़ाइल को पंक्ति में लिखें (स्पष्ट रूप से एक अलग फ़ाइल यदि आप उन्हें अलग रखना चाहते हैं)।

यदि आपको विभिन्न सेटों पर और प्रसंस्करण करने की आवश्यकता है, तो पंक्ति संख्या को स्टोर न करने पर, पूरी पंक्ति को संग्रहीत करने के बजाय। फिर जब आप पंक्तियों के साथ करते हैं तो आप पंक्ति को फिर से लाने के लिए पंक्ति संख्या की आवश्यकता होती है।

एनबी: पंक्ति संख्या संग्रहित करने के बजाय, आप ऑफ़सेट को पंक्ति के प्रारंभ बिंदु की फ़ाइल में संग्रहीत कर सकते हैं। फिर यदि आपको आवश्यकता हो, तो आप फ़ाइल तक पहुंच सकते हैं और पंक्तियों को यादृच्छिक रूप से पढ़ सकते हैं।

बस इस उत्तर को आपके किसी भी प्रश्न (या स्पष्टीकरण) के साथ टिप्पणी करें, मैं जवाब अपडेट करूंगा, मैं वैसे भी कुछ और घंटों के लिए यहां रहूंगा।

संपादित
आप कुंजी भंडारण नहीं है, लेकिन चाबियों का हैश भंडारण के द्वारा आगे स्मृति पैर प्रिंट कम कर सकते हैं। यदि आपको डुप्लिकेट मिलता है, तो फ़ाइल में उस स्थिति की तलाश करें, पंक्ति को दोबारा पढ़ें और वास्तविक कुंजी की तुलना करें।

+0

कृपया उपरोक्त संपादित पोस्ट में मेरा उत्तर देखें। क्षमा करें, टिप्पणियों में कोड नमूना सफलतापूर्वक पेस्ट करने के बारे में नहीं पता था। – user262102

2

यदि आपको डॉटट्रेस की तरह इस पर एक प्रोफाइलर नहीं मिला है, तो यह देखने के लिए कि कौन सी वस्तुएं स्मृति का उपयोग कर रही हैं, जो आपको अनुकूलन की आवश्यकता के बारे में एक अच्छा विचार देगी।

आप listDupExp स्टोर करने के लिए की जरूरत है:

कोड में देखने से कुछ विचार? मुझे सूची के साथ लगता है कि आप दोनों फ़ाइलों को स्मृति में प्रभावी रूप से लोड कर रहे हैं, इसलिए 2 x 150MB + कुछ ओवरहेड आसानी से कार्य प्रबंधक में 500 एमबी तक पहुंच सकता है।

दूसरा, क्या आप सभी इनपुट पढ़ने से पहले आउटपुट लिखना शुरू कर सकते हैं? मुझे लगता है कि यह मुश्किल है क्योंकि ऐसा लगता है कि आपको लिखने से पहले सॉर्ट किए गए सभी आउटपुट आइटमों की आवश्यकता होती है, लेकिन ऐसा कुछ हो सकता है जिसे आप देख सकते हैं।

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