मैंने एक शब्द को एक बार गिनने के लिए उसे दो बार हैश कर दिया
पिछले हफ्ते मैंने एक लॉग पार्सर (log parser) का प्रोफाइलिंग किया। यह एक दैनिक लॉग में एरर कोड (error codes) गिनता है। इसका मुख्य लॉजिक एक साधारण डिक्शनरी अपडेट है।
अधिकांश डेवलपर्स इसे इस तरह लिखते हैं:
if (counts.TryGetValue(code, out int c))
counts[code] = c + 1;
else
counts[code] = 1;
यह कोड की (key) को दो बार हैश करता है। TryGetValue हैश की गणना करके और बकेट (bucket) को स्कैन करके एंट्री ढूँढता है। फिर इंडेक्सर (indexer) वैल्यू अपडेट करने के लिए बिल्कुल वही काम दोबारा करता है। आप प्रति टोकन एक ही की और एक ही हैश पर दो बार CPU साइकिल बर्बाद करते हैं।
आप दूसरे स्टेप को छोड़ सकते हैं। CollectionsMarshal.GetValueRefOrAddDefault का उपयोग करें।
ref int slot = ref CollectionsMarshal.GetValueRefOrAddDefault(counts, code, out _);
slot++;
यह मेथड एक ही स्टेप में स्लॉट को ढूँढता है या बनाता है। यह आपको सीधे स्टोरेज का रेफरेंस (reference) देता है। आप केवल एक बार हैश करते हैं और एक बार बकेट स्कैन करते हैं। फिर आप वैल्यू को वहीं (in place) बदल देते हैं।
मैंने इसका परीक्षण 5 मिलियन टोकन के साथ किया।
परिणाम: • TryGetValue + indexer: 160.0 ms • GetValueRefOrAddDefault: 95.0 ms
एकल-लुकअप (one-lookup) वाला वर्ज़न 1.7x तेज़ है।
महत्वपूर्ण बात यह है कि मेमोरी एलोकेशन (memory allocations) बिल्कुल समान रहे। यह ट्रिक मेमोरी नहीं बचाती है। यह केवल CPU बचाती है। यदि आपका कोड गार्बेज कलेक्शन (garbage collection) के कारण धीमा है, तो इस बदलाव से कोई फर्क नहीं पड़ेगा। यदि आपका कोड भारी गणना (heavy counting) के कारण धीमा है, तो यह मददगार है।
इसका उपयोग तब करें जब आपका लूप मौजूदा कीज़ (keys) में कई अपडेट करता है। जैसे-जैसे इंसर्ट (inserts) की तुलना में अपडेट का अनुपात बढ़ता है, इसका लाभ भी बढ़ता जाता है।
एक चेतावनी: यह रेफरेंस डिक्शनरी के इंटरनल स्टोरेज की ओर इशारा करता है। यह केवल अगले स्ट्रक्चरल बदलाव (structural change) तक ही मान्य रहता है। यदि आप कीज़ जोड़ते या हटाते हैं, तो रेफरेंस को होल्ड न करें। रेफरेंस लें, वैल्यू बदलें, और आगे बढ़ें।
अधिकांश कार्यों के लिए TryGetValue का उपयोग करें। इसे पढ़ना आसान है। ref वर्ज़न का उपयोग केवल तभी करें जब आपका डिक्शनरी लूप परफॉरमेंस बॉटलनेक (performance bottleneck) बन रहा हो।
Source: https://dev.to/ssukhpinder/i-hashed-every-word-twice-to-count-it-once-1mg9
