- 1BRC: 1 अरब पंक्तियों वाली टेक्स्ट फ़ाइल से तापमान मापन मान पढ़कर प्रत्येक ऑब्ज़र्वेशन स्टेशन के लिए न्यूनतम/औसत/अधिकतम तापमान की गणना करने वाला कोड लिखने की चुनौती
- यह 1 जनवरी 2024 से 31 जनवरी तक चला, और लक्ष्य था कि नवीनतम Java का अधिकतम उपयोग किया जाए
- इसके बाद लोगों ने रुचि लेकर अलग-अलग भाषाओं (Rust, Go, C++, SQL) में इसे आज़माना शुरू किया
- Go में लिखे गए 9 समाधानों का विस्तार से परिचय दिया गया है (सबसे धीमे से सबसे तेज़ क्रम में)
मूल मापदंड
cat कमांड का उपयोग करके 1 अरब पंक्तियों वाले टेक्स्ट डेटा (13GB) को पढ़ने में 1.052 सेकंड लगते हैं।
- वास्तव में फ़ाइल को प्रोसेस करने वाली
wc कमांड को लगभग 1 मिनट लगता है (55.710 सेकंड)।
- AWK समाधान से इस समस्या को हल करने में 7 मिनट 35 सेकंड लगते हैं।
समाधान 1: सरल और idiomatic Go
- Go standard library का उपयोग करने वाले पहले समाधान में 1 मिनट 45 सेकंड लगे।
bufio.Scanner से पंक्तियाँ पढ़ी जाती हैं और strings.Cut से ';' के आधार पर उन्हें विभाजित किया जाता है।
strconv.ParseFloat से तापमान parse किया जाता है, और Go map का उपयोग करके परिणामों को संचित किया जाता है।
समाधान 2: pointer values वाला map
- map में दो बार hashing से बचने के लिए
map[string]*stats का उपयोग किया गया।
- pointer values का उपयोग करके समय 1 मिनट 45 सेकंड से घटाकर 1 मिनट 31 सेकंड किया गया।
समाधान 3: strconv.ParseFloat से बचना
strconv.ParseFloat की जगह custom code से तापमान parse किया गया।
- समय 1 मिनट 31 सेकंड से घटकर 55.8 सेकंड हो गया।
समाधान 4: fixed-point integer का उपयोग
- floating-point operations से बचने के लिए तापमान को integer के रूप में व्यक्त किया गया।
- समय 55.8 सेकंड से घटकर 51.0 सेकंड हो गया।
समाधान 5: bytes.Cut से बचना
- ';' खोजने के लिए पूरे station name को scan करने के बजाय अंत से parse किया गया।
- समय 51.0 सेकंड से घटकर 46.0 सेकंड हो गया।
समाधान 6: bufio.Scanner से बचना
bufio.Scanner को हटाकर फ़ाइल को बड़े chunks में पढ़ा गया।
- समय 46.0 सेकंड से घटकर 41.3 सेकंड हो गया।
समाधान 7: custom hash table
- Go के map की जगह custom hash table implement किया गया।
- समय 41.3 सेकंड से घटकर 25.8 सेकंड हो गया।
समाधान 8: chunk parallel processing
- सरल और idiomatic code को parallelize करके समय 1 मिनट 45 सेकंड से घटाकर 24.3 सेकंड किया गया।
समाधान 9: सभी optimizations और parallel processing
- सभी optimizations को parallel processing के साथ जोड़कर समय 24.3 सेकंड से घटाकर 3.99 सेकंड किया गया।
परिणाम तालिका
- सभी Go समाधानों और सबसे तेज़ Go तथा Java समाधानों की तुलना करने वाली तालिका दी गई है।
- Go संस्करणों में सबसे तेज़ 2.90 सेकंड में चला, जबकि Java संस्करण ने 0.953 सेकंड में प्रोसेस किया।
- 1 सेकंड से भी कम समय लेने वाला Java संस्करण Thomas Wuerthinger (GraalVM के निर्माता) ने बनाया था, इसलिए संभवतः यह उनके विशेषज्ञ होने की वजह से संभव हुआ।
अंतिम टिप्पणी
- रोज़मर्रा के programming tasks में सरल और idiomatic code एक अच्छा शुरुआती बिंदु है।
- यदि आप data processing pipeline बना रहे हैं, तो code को 4 गुना या 26 गुना तेज़ बनाना user satisfaction बढ़ा सकता है और computing cost बचा सकता है।
- यदि आप runtime या interpreter बना रहे हैं, तो performance improvement महत्वपूर्ण है।
GN⁺ की राय
- यह लेख Go भाषा का उपयोग करके बड़े पैमाने पर data processing को optimize करने के कई तरीकों की पड़ताल करता है और performance optimization पर एक दिलचस्प case study पेश करता है।
- यह दिखाता है कि optimization प्रक्रिया में Go standard library से आगे बढ़कर custom hash table जैसी data structures को implement करना महत्वपूर्ण भूमिका निभा सकता है।
- यह parallel processing के प्रभाव पर ज़ोर देता है और दिखाता है कि single-core optimization और parallelization को मिलाकर चौंकाने वाला performance gain हासिल किया जा सकता है।
- performance-sensitive applications विकसित करने वाले software engineers के लिए यह लेख उपयोगी insights देता है।
- ऐसे optimizations वास्तविक production environment में कितने उपयोगी होंगे, यह use case पर निर्भर करता है। हर application को इस स्तर की optimization की आवश्यकता नहीं होती।
6 टिप्पणियां
मुझे जिज्ञासा है कि step 7 में खास तौर पर कौन-सा काम किया गया था। परफॉर्मेंस में बहुत बड़ा सुधार वहीं हुआ लगता है lol
दिलचस्प है कि इसमें हर step के हिसाब से performance improvement का समय अलग-अलग दिखाया गया है, हाहा
wcसे भी 1 मिनट में हो जाता है.... सच में, सबसे बढ़िया वही है जब कोड लिखना ही न पड़े... हा हाअच्छा लेख साझा करने के लिए धन्यवाद। इसे पढ़कर वह समय याद आ गया जब मैं सिस्टम optimization को लेकर दीवाना था, हाहा।
जैसे-जैसे मेरा development career बढ़ता गया, मुझे बार-बार यह अनुभव हुआ कि सबसे ज़्यादा optimized code को maintain करना मुश्किल होता है, इसलिए organizational environment में उसे चलाना भी कठिन हो जाता है। इसी वजह से मैं धीरे-धीरे optimization के रास्ते से दूर होता गया। (अचानक निजी आत्मचिंतन)
संगठन के लिए अनुकूलित कोड!!
Hacker News टिप्पणियाँ
cat,wcआदि का उपयोग करके baseline measurement प्राप्त करने वाला पहला सेक्शन खास तौर पर दिलचस्प था। उनका मानना था कि यह एक "उचित" रेंज पाने का आसान तरीका है।unsafe.Pointerका उपयोग करके बिना boundary check के memory read करना, standard library केbytesऔरbitsपैकेज के functions का assembly में लिखा होना, garbage collection बंद करने की setting, और goroutine को thread पर pin करने के तरीके शामिल हैं।awk,grepआदि एक स्तर तेज़ हो जाते हैं, और दावा किया किawksolution मेंLC_ALL=Cजोड़ने से processing time 1 मिनट के भीतर लाया जा सकता है।