నేను ప్రతి పదాన్ని ఒకసారి లెక్కించడానికి రెండుసార్లు హాష్ చేశాను
నేను గత వారం ఒక లాగ్ పార్సర్ను ప్రొఫైల్ చేశాను. ఇది రోజువారీ లాగ్లోని ఎర్రర్ కోడ్లను లెక్కిస్తుంది. దీని ప్రధాన లాజిక్ ఒక సాధారణ డిక్షనరీ అప్డేట్.
చాలా మంది డెవలపర్లు దీనిని ఇలా రాస్తారు:
if (counts.TryGetValue(code, out int c))
counts[code] = c + 1;
else
counts[code] = 1;
ఈ కోడ్ కీని రెండుసార్లు హాష్ చేస్తుంది. TryGetValue అనేది హాష్ను లెక్కించడం మరియు బకెట్ను వెతకడం (walking the bucket) ద్వారా ఎంట్రీని కనుగొంటుంది. ఆ తర్వాత, విలువను అప్డేట్ చేయడానికి ఇండెక్సర్ మళ్ళీ అదే పనిని చేస్తుంది. మీరు ప్రతి టోకెన్కు ఒకే కీ మరియు ఒకే హాష్పై రెండుసార్లు CPU సైకిల్లను వృథా చేస్తున్నారు.
మీరు ఆ రెండో దశను దాటవేయవచ్చు. CollectionsMarshal.GetValueRefOrAddDefault ఉపయోగించండి.
ref int slot = ref CollectionsMarshal.GetValueRefOrAddDefault(counts, code, out _);
slot++;
ఈ మెథడ్ ఒకే దశలో స్లాట్ను కనుగొంటుంది లేదా సృష్టిస్తుంది. ఇది మీకు స్టోరేజీకి నేరుగా రిఫరెన్స్ను ఇస్తుంది. మీరు ఒకే ఒక హాష్ మరియు ఒకే ఒక బకెట్ వాక్ చేస్తారు. ఆ తర్వాత మీరు విలువను అక్కడికక్కడే (in place) మారుస్తారు.
నేను దీనిని 5 మిలియన్ టోకెన్లతో పరీక్షించాను.
ఫలితాలు: • TryGetValue + indexer: 160.0 ms • GetValueRefOrAddDefault: 95.0 ms
ఒకేసారి లుకప్ చేసే వెర్షన్ 1.7x వేగంగా ఉంది.
ముఖ్యంగా, మెమరీ అలోకేషన్లు (memory allocations) ఒకేలా ఉన్నాయి. ఈ ట్రిక్ మెమరీని ఆదా చేయదు. ఇది కేవలం CPUని మాత్రమే ఆదా చేస్తుంది. మీ కోడ్ గార్బేజ్ కలెక్షన్ (garbage collection) వల్ల నెమ్మదిగా ఉంటే, ఈ మార్పు వల్ల ఉపయోగం ఉండదు. ఒకవేళ మీ కోడ్ భారీ లెక్కల (heavy counting) వల్ల నెమ్మదిగా ఉంటే, ఇది సహాయపడుతుంది.
మీ లూప్ ఇప్పటికే ఉన్న కీలకు అనేక అప్డేట్లను చేస్తున్నప్పుడు దీనిని ఉపయోగించండి. అప్డేట్లకు మరియు ఇన్సర్ట్లకు మధ్య నిష్పత్తి పెరిగే కొద్దీ దీని ప్రయోజనం పెరుగుతుంది.
ఒక హెచ్చరిక: ఈ రిఫరెన్స్ అంతర్గత డిక్షనరీ స్టోరేజీని సూచిస్తుంది. తదుపరి స్ట్రక్చరల్ మార్పు (structural change) వచ్చే వరకు మాత్రమే ఇది చెల్లుబాటు అవుతుంది. మీరు కీలను జోడించినా లేదా తొలగించినా ఆ రిఫరెన్స్ను పట్టుకుని ఉండకండి. రిఫరెన్స్ను తీసుకోండి, విలువను మార్చండి, మరియు ముందుకు సాగండి.
చాలా పనుల కోసం TryGetValue ఉపయోగించండి. ఇది చదవడానికి సులభంగా ఉంటుంది. మీ డిక్షనరీ లూప్ పెర్ఫార్మెన్స్ బాటిల్నెక్ (performance bottleneck) గా ఉన్నప్పుడు మాత్రమే ref వెర్షన్ను ఉపయోగించండి.
మూలం: https://dev.to/ssukhpinder/i-hashed-every-word-twice-to-count-it-once-1mg9
