میں نے ہر لفظ کو ایک بار گننے کے لیے دو بار ہیش کیا
میں نے گزشتہ ہفتے ایک لاگ پارسر (log parser) کی پروفائلنگ کی۔ یہ روزانہ کے لاگ میں ایرر کوڈز (error codes) کو گنتا ہے۔ اس کا بنیادی منطق (logic) ایک سادہ ڈکشنری اپ ڈیٹ ہے۔
زیادہ تر ڈویلپرز اسے اس طرح لکھتے ہیں:
if (counts.TryGetValue(code, out int c))
counts[code] = c + 1;
else
counts[code] = 1;
یہ کوڈ کی (key) کو دو بار ہیش کرتا ہے۔ TryGetValue ہیش کا حساب لگا کر اور بکٹ (bucket) میں تلاش کر کے انٹری تلاش کرتا ہے۔ پھر انڈیکسر (indexer) ویلیو کو اپ ڈیٹ کرنے کے لیے بالکل وہی کام دوبارہ کرتا ہے۔ آپ ہر ٹوکن (token) کے لیے ایک ہی کی اور ایک ہی ہیش پر دو بار CPU سائیکلز ضائع کرتے ہیں۔
آپ دوسرے مرحلے کو چھوڑ سکتے ہیں۔ CollectionsMarshal.GetValueRefOrAddDefault کا استعمال کریں۔
ref int slot = ref CollectionsMarshal.GetValueRefOrAddDefault(counts, code, out _);
slot++;
یہ طریقہ ایک ہی مرحلے میں سلاٹ (slot) تلاش کرتا ہے یا اسے تخلیق کرتا ہے۔ یہ آپ کو براہ راست اسٹوریج کا ریفرنس (reference) دیتا ہے۔ آپ ایک بار ہیش کرتے ہیں اور ایک بار بکٹ میں تلاش کرتے ہیں۔ پھر آپ وہیں پر ویلیو کو تبدیل کر دیتے ہیں۔
میں نے اسے 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) تک ہی کارآمد رہتا ہے۔ اگر آپ کیز (keys) شامل یا حذف کر رہے ہوں تو ریفرنس کو برقرار نہ رکھیں۔ ریفرنس حاصل کریں، ویلیو تبدیل کریں، اور آگے بڑھ جائیں۔
زیادہ تر کاموں کے لیے TryGetValue استعمال کریں۔ اسے پڑھنا آسان ہے۔ ریفرنس ورژن کا استعمال صرف تب کریں جب آپ کے ڈکشنری لوپ کی وجہ سے کارکردگی میں رکاوٹ (performance bottleneck) آ رہی ہو۔
Source: https://dev.to/ssukhpinder/i-hashed-every-word-twice-to-count-it-once-1mg9
