इस कैशिंग रणनीति के लिए मुझे किस डेटा संरचना का उपयोग करना चाहिए?


11

मैं एक .NET 4.0 एप्लिकेशन पर काम कर रहा हूं, जो एक डबल रिटर्न करने वाले दो डबल्स पर अधिक महंगी गणना करता है। यह गणना कई हजार वस्तुओं में से प्रत्येक के लिए की जाती है । इन गणनाओं को Taskथ्रेडपूल धागे पर किया जाता है ।

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

इसे लागू करने के लिए, मैं इनपुट्स और कैश्ड परिणामों को संग्रहीत करने के लिए Dictionary<Input, double>(जहां Inputदो इनपुट डबल मानों को संग्रहीत करने वाला एक मिनी-क्लास होगा) का उपयोग करने के बारे में सोच रहा था । हालांकि, अंतिम बार जब किसी परिणाम का उपयोग किया गया था, तो मुझे भी नज़र रखने की आवश्यकता होगी। इसके लिए मुझे लगता है कि जब कैश भरा जा रहा था, तो मुझे तानाशाही से एक परिणाम निकालने की आवश्यकता होगी, जिसमें मुझे जानकारी संग्रहीत करने के लिए दूसरे संग्रह की आवश्यकता होगी। मुझे चिंता है कि लगातार इस सूची को बनाए रखने से प्रदर्शन पर नकारात्मक असर पड़ेगा।

क्या ऐसा करने का एक बेहतर (यानी अधिक प्रदर्शन करने वाला) तरीका है, या शायद एक सामान्य डेटा संरचना भी है जिससे मैं अनजान हूं? अपने समाधान की अनुकूलता निर्धारित करने के लिए मुझे किस प्रकार की चीजों की रूपरेखा / माप करनी चाहिए?

जवाबों:


12

यदि आप LRU बेदखली कैश का उपयोग करना चाहते हैं (कम से कम हाल ही में इस्तेमाल किया गया बेदखल), तो संभवतः उपयोग करने के लिए डेटा संरचनाओं का एक अच्छा संयोजन है:

  • परिपत्र से जुड़ी सूची (प्राथमिकता कतार के रूप में)
  • शब्दकोश

इसलिए:

  • लिंक की गई सूची में O (1) सम्मिलन और हटाने का समय है
  • सूची पूर्ण होने पर सूची नोड्स का पुन: उपयोग किया जा सकता है और अतिरिक्त आवंटन की आवश्यकता नहीं है।

यह है कि बुनियादी एल्गोरिथ्म को कैसे काम करना चाहिए:

डेटा संरचनाओं

LinkedList<Node<KeyValuePair<Input,Double>>> list; Dictionary<Input,Node<KeyValuePair<Input,Double>>> dict;

  1. इनपुट मिला है
  2. यदि शब्दकोश में कुंजी है
    • नोड में संग्रहीत मान लौटाएं और नोड को सूची की शुरुआत में स्थानांतरित करें
  3. यदि शब्दकोश में कुंजी नहीं है
    • मूल्य की गणना करें
    • मूल्य को सूची के अंतिम नोड में संग्रहीत करें
    • यदि अंतिम में मान नहीं है, तो पिछली कुंजी को शब्दकोश से हटा दें
    • अंतिम नोड को पहले स्थान पर ले जाएं।
    • शब्दकोश (इनपुट, नोड) कुंजी मूल्य जोड़ी में स्टोर करें।

इस दृष्टिकोण के कुछ लाभ हैं, शब्दकोश मूल्य ओ (1) को पढ़ना और सेट करना, लिंक की गई सूची में एक नोड को सम्मिलित करना और हटाना ओ (1) है, जिसका अर्थ है कि एल्गोरिथ्म मूल्यों के पढ़ने और लिखने के लिए ओ (1) आ रहा है। कैश के लिए, और मेमोरी आवंटन से बचा जाता है और मेमोरी कॉपी ऑपरेशन को ब्लॉक कर देता है, जिससे यह मेमोरी पॉइंट से स्थिर हो जाता है।


अच्छे अंक, अब तक का सबसे अच्छा विचार, IMHO। मैंने आज के आधार पर एक कैश लागू किया और इसे प्रोफाइल करना होगा और देखना होगा कि यह कल कितना अच्छा प्रदर्शन करता है।
PersonalNexus

3

ऐसा लगता है कि औसत पीसी में आपके निपटान में आपके पास प्रसंस्करण शक्ति को देखते हुए एक ही गणना के लिए जाने के लिए बहुत प्रयास करना पड़ता है। इसके अलावा, आपके पास प्रत्येक अद्वितीय जोड़ी मूल्यों के लिए अपनी गणना के लिए पहली कॉल का खर्च अभी भी होगा, इसलिए 100,000 अद्वितीय मूल्य जोड़े अभी भी आपको समय n * 100,000 न्यूनतम पर खर्च होंगे । इस बात पर विचार करें कि जैसे ही शब्दकोश बड़ा होगा, आपके शब्दकोश में मानों की पहुँच धीमी हो जाएगी। क्या आप अपने शब्दकोष की गति की गारंटी दे सकते हैं जो आपकी गणना की गति के विरुद्ध उचित रिटर्न प्रदान करने के लिए पर्याप्त क्षतिपूर्ति करेगा।

भले ही, यह लगता है जैसे आप शायद अपने एल्गोरिथ्म का अनुकूलन करने के लिए एक साधन खोजने पर विचार करने की आवश्यकता होगी। इसके लिए आपको एक प्रोफाइलिंग टूल की आवश्यकता होगी, जैसे कि Redgate चींटियों को देखने के लिए कि अड़चनें कहां हैं, और यह निर्धारित करने में आपकी सहायता करने के लिए कि क्या आप कुछ ऐसे ओवरहेड्स को कम करने के तरीके हैं, जो आपके पास क्लास इंस्टेंसेस, लिस्ट ट्रैंगल, डेटाबेस से संबंधित हो सकते हैं एक्सेस करता है, या जो कुछ भी है वह आपको इतना समय दे रहा है।


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

0

एक विचार है कि केवल कैश एन परिणाम क्यों है? यहां तक ​​कि अगर n 300,000 है, तो आप केवल 7.2MB मेमोरी का उपयोग करेंगे (प्लस तालिका संरचना के लिए जो भी अतिरिक्त है)। यह तीन 64 बिट डबल्स को मानता है। यदि आप मेमोरी स्पेस से बाहर निकलने के बारे में चिंतित नहीं हैं, तो आप केवल जटिल कैल्सीशन रूटीन में ही मेमोएशन लागू कर सकते हैं।


वहाँ सिर्फ एक कैश नहीं होगा, लेकिन एक "आइटम" जो मैं विश्लेषण कर रहा हूं, और इनमें से कई सौ-हजार आइटम हो सकते हैं।
PersonalNexus

किस तरह से यह मायने रखता है कि इनपुट किस 'आइटम' से आता है? क्या इसके साइड इफेक्ट्स हैं?
जे.के.

@jk। विभिन्न आइटम गणना के लिए बहुत अलग इनपुट का उत्पादन करेंगे। चूंकि इसका मतलब है कि थोड़ा ओवरलैप होगा, मुझे नहीं लगता कि उन्हें एक कैश में रखना समझ में आता है। इसके अलावा, विभिन्न वस्तुएं अलग-अलग धागों में रह सकती हैं, इसलिए साझा स्थिति से बचने के लिए, मैं कैश को अलग रखना चाहूंगा।
PersonalNexus

@PersonalNexus मुझे लगता है कि गणना में शामिल होने के लिए अधिक 2 पैरामीटर हैं? एल्विस, आप अभी भी मूल रूप से एफ (एक्स, वाई) = कुछ सामान करते हैं। प्लस साझा राज्य ऐसा लगता है कि यह बाधा के बजाय प्रदर्शन में मदद करेगा?
पीटर स्मिथ

@PeterSmith दो पैरामीटर मुख्य इनपुट हैं। अन्य हैं, लेकिन वे शायद ही कभी बदलते हैं। अगर वे ऐसा करते हैं, तो मैं पूरा कैश निकाल दूंगा। "साझा स्थिति" से मेरा मतलब सभी या वस्तुओं के समूह के लिए एक साझा कैश से है। चूँकि इसे किसी अन्य तरीके से लॉक या सिंक्रनाइज़ करने की आवश्यकता होगी, यह प्रदर्शन में बाधा उत्पन्न करेगा। साझा स्थिति के प्रदर्शन निहितार्थ पर अधिक
PersonalNexus

0

दूसरे संग्रह के साथ दृष्टिकोण ठीक है। यह एक प्राथमिकता कतार होनी चाहिए जो न्यूनतम मानों को जल्दी से हटाने / हटाने की अनुमति देता है और कतार के भीतर प्राथमिकताओं को बदल रहा है (बढ़ती है) (बाद वाला भाग सबसे कठिन है, सबसे सरल प्राउ कतार के कार्यान्वयन द्वारा समर्थित नहीं है)। सी 5 पुस्तकालय इस तरह के एक संग्रह है, यह कहा जाता है है IntervalHeap

या बेशक, आप अपना खुद का संग्रह बनाने की कोशिश कर सकते हैं, जैसे कुछ SortedDictionary<int, List<InputCount>>। ( अपने मूल्य के साथ अपने डेटा के InputCountसंयोजन का वर्ग होना चाहिए )InputCount

उस गणना को अपडेट करना जब किसी तत्व को हटाकर और फिर से सम्मिलित करके आपके गणना मूल्य को परिवर्तित किया जा सकता है।


0

जैसा कि पीटर स्मिथ के जवाब में कहा गया है, जिस पैटर्न को आप लागू करने की कोशिश कर रहे हैं, उसे संस्मरण कहा जाता है । सी # में साइड इफेक्ट के बिना पारदर्शी तरीके से ज्ञापन को लागू करना काफी कठिन है। ऑलिवर स्टर्म की पुस्तक C # में कार्यात्मक प्रोग्रामिंग में एक समाधान देता है (कोड डाउनलोड के लिए उपलब्ध है, अध्याय 10)।

F # में यह बहुत आसान होगा। बेशक, यह एक अन्य प्रोग्रामिंग भाषा का उपयोग शुरू करने का एक बड़ा निर्णय है, लेकिन यह विचार करने योग्य हो सकता है। विशेष रूप से जटिल गणनाओं में, संस्मरण की तुलना में अधिक चीजों को प्रोग्राम करना आसान बनाने के लिए बाध्य है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.