Go में कंकरेंसी और मल्टीथ्रेडिंग: एडवांस्ड लेवल
\n\nकंकरेंसी (concurrency) Go भाषा की एक प्रमुख विशेषता है, जो इसकी आर्किटेक्चर में रनटाइम और सिंटैक्स स्तर पर शामिल है। कई अन्य भाषाओं के विपरीत, जहां मल्टीथ्रेडिंग को जटिल लाइब्रेरीज़ के माध्यम से लागू किया जाता है और थ्रेड्स को मैन्युअल रूप से प्रबंधित करना पड़ता है, Go हल्के गोरूटीन (goroutines) और चैनल (channels) प्रदान करता है। एडवांस्ड स्तर पर, केवल कई कार्यों को चलाना ही नहीं, बल्कि उन्हें सही ढंग से सिंक्रोनाइज़ करना, डेटा रेस से बचना और सिस्टम संसाधनों का कुशलतापूर्वक उपयोग करना महत्वपूर्ण है। इस लेख में, हम Go में कंकरेंसी के साथ काम करने की एडवांस्ड तकनीकों पर चर्चा करेंगे।
\n\n1. गोरूटीन: जीवनचक्र प्रबंधन और प्राथमिकताएँ
\n\nगोरूटीन हल्के थ्रेड होते हैं जो Go रनटाइम द्वारा प्रबंधित किए जाते हैं। इन्हें go कीवर्ड की मदद से शुरू किया जाता है। हालांकि, एडवांस्ड स्तर पर यह समझना ज़रूरी है कि उनके निष्पादन और समाप्ति को कैसे नियंत्रित किया जाए।
गोरूटीन का बेसिक लॉन्च:
\npackage main\n\nimport (\n "fmt"\n "time"\n)\n\nfunc worker(id int) {\n fmt.Printf("Worker %d शुरू\\n", id)\n time.Sleep(time.Second)\n fmt.Printf("Worker %d समाप्त\\n", id)\n}\n\nfunc main() {\n for i := 1; i <= 5; i++ {\n go worker(i)\n }\n time.Sleep(2 * time.Second) // अस्थायी उपाय: समाप्ति की प्रतीक्षा\n}\n\nसमस्या: इस उदाहरण में हम प्रतीक्षा के लिए time.Sleep का उपयोग कर रहे हैं, जो अविश्वसनीय है। एडवांस्ड स्तर पर चैनल और sync.WaitGroup का उपयोग किया जाता है।
2. sync.WaitGroup के साथ सिंक्रोनाइज़ेशन
\n\nsync.WaitGroup आपको दी गई संख्या में गोरूटीन के पूरा होने की प्रतीक्षा करने की अनुमति देता है। यह सिंक्रोनाइज़ेशन के लिए एक बुनियादी लेकिन शक्तिशाली उपकरण है।
package main\n\nimport (\n "fmt"\n "sync"\n "time"\n)\n\nfunc worker(id int, wg *sync.WaitGroup) {\n defer wg.Done() // समाप्त होने पर काउंटर घटाएं\n fmt.Printf("Worker %d शुरू\\n", id)\n time.Sleep(time.Second)\n fmt.Printf("Worker %d समाप्त\\n", id)\n}\n\nfunc main() {\n var wg sync.WaitGroup\n for i := 1; i <= 5; i++ {\n wg.Add(1) // शुरू करने से पहले काउंटर बढ़ाएं\n go worker(i, &wg)\n }\n wg.Wait() // काउंटर शून्य होने तक ब्लॉक करें\n fmt.Println("सभी कार्य पूरे हो गए")\n}\n\nमहत्वपूर्ण: wg.Add() को गोरूटीन शुरू करने से पहले कॉल किया जाना चाहिए, अन्यथा डेटा रेस हो सकती है। पैनिक की स्थिति में भी काउंटर घटाने की गारंटी के लिए गोरूटीन के अंदर defer wg.Done() का उपयोग करें।
3. चैनल: बफरिंग, दिशा और select
\n\nचैनल गोरूटीन के बीच डेटा आदान-प्रदान का मुख्य तंत्र हैं। एडवांस्ड स्तर पर बफ़र्ड चैनल, यूनिडायरेक्शनल चैनल और select ऑपरेटर का उपयोग किया जाता है।
3.1. बफ़र्ड चैनल
\nबफ़र्ड चैनल तुरंत प्राप्त किए बिना डेटा भेजने की अनुमति देते हैं। इससे ब्लॉकिंग कम होती है और थ्रूपुट बढ़ता है।
\npackage main\n\nimport "fmt"\n\nfunc main() {\n ch := make(chan int, 3) // 3 एलिमेंट के बफर वाला चैनल\n ch <- 1\n ch <- 2\n ch <- 3\n // ch <- 4 // ब्लॉक होगा, क्योंकि बफर भरा है\n fmt.Println(<-ch)\n fmt.Println(<-ch)\n fmt.Println(<-ch)\n}\n\n3.2. यूनिडायरेक्शनल चैनल
\nटाइप सुरक्षा और चैनल की भूमिका को स्पष्ट रूप से इंगित करने के लिए यूनिडायरेक्शनल चैनल का उपयोग किया जाता है: chan<- (केवल भेजना) और <-chan (केवल प्राप्त करना)।
package main\n\nimport "fmt"\n\nfunc sender(out chan<- int) {\n for i := 0; i < 5; i++ {\n out <- i\n }\n close(out)\n}\n\nfunc receiver(in <-chan int) {\n for val := range in {\n fmt.Println(val)\n }\n}\n\nfunc main() {\n ch := make(chan int)\n go sender(ch)\n receiver(ch)\n}\n\n3.3. select ऑपरेटर
\nselect एक गोरूटीन को एक साथ कई चैनलों पर प्रतीक्षा करने की अनुमति देता है। यह