एका शब्दाची गणना करण्यासाठी मी दोनदा हॅश केला
गेल्या आठवड्यात मी एका लॉग पार्सरचे (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) देते. तुम्ही एकदाच हॅश आणि एकदाच बकेट शोधता. त्यानंतर तुम्ही व्हॅल्यू थेट तिथेच बदलता (mutate).
मी ५ दशलक्ष (5 million) टोकन्ससह याची चाचणी केली.
निकाल: • TryGetValue + indexer: 160.0 ms • GetValueRefOrAddDefault: 95.0 ms
एक-लुकअप (one-lookup) आवृत्ती 1.7x वेगाने काम करते.
महत्त्वाची गोष्ट म्हणजे, मेमरी अलोकेशन (memory allocation) तंतोतंत सारखेच राहिले. ही ट्रिक मेमरी वाचवत नाही. ती फक्त CPU वाचवते. जर तुमचा कोड गार्बेज कलेक्शनमुळे (garbage collection) संथ असेल, तर या बदलामुळे काहीही फरक पडणार नाही. जर तुमचा कोड मोठ्या प्रमाणावरील गणनेमुळे (heavy counting) संथ असेल, तर यामुळे मदत होईल.
जेव्हा तुमचे लूप अस्तित्वात असलेल्या कीजमध्ये (existing keys) अनेक अपडेट्स करते, तेव्हा याचा वापर करा. अपडेट्स आणि इन्सर्ट्सचे (inserts) प्रमाण जितके जास्त असेल, तितका याचा फायदा वाढतो.
एक चेतावणी: हा संदर्भ (reference) डिक्शनरीच्या अंतर्गत स्टोरेजला निर्देशित करतो. जोपर्यंत पुढील स्ट्रक्चरल बदल (structural change) होत नाही, तोपर्यंतच तो वैध राहतो. जर तुम्ही कीज जोडल्या किंवा काढून टाकल्या, तर तो संदर्भ धरून ठेवू नका. फक्त ref घ्या, व्हॅल्यू बदला आणि पुढे जा.
बहुतेक कामांसाठी TryGetValue वापरा. ते वाचायला सोपे आहे. ref आवृत्तीचा वापर तेव्हाच करा जेव्हा तुमच्या डिक्शनरी लूपमुळे परफॉर्मन्समध्ये अडथळा (performance bottleneck) येत असेल.
Source: https://dev.to/ssukhpinder/i-hashed-every-word-twice-to-count-it-once-1mg9
