Go में समवर्तीता और मल्टीथ्रेडिंग: गोरूटीन से चैनल तक
Go भाषा (Golang) को Google में प्रदर्शन और स्केलेबिलिटी की आधुनिक आवश्यकताओं को ध्यान में रखकर विकसित किया गया था। इसकी मुख्य "विशेषता" — समवर्तीता के लिए अंतर्निहित समर्थन है, जो बाहरी लाइब्रेरी के माध्यम से नहीं, बल्कि भाषा स्तर पर लागू किया गया है। Python के विपरीत, जहाँ मल्टीथ्रेडिंग GIL (Global Interpreter Lock) द्वारा सीमित है, Go हल्के गोरूटीन प्रदान करता है, जो एक साथ हजारों कार्यों को कुशलतापूर्वक निष्पादित करने की अनुमति देता है। इस लेख में, हम Go में समवर्तीता और मल्टीथ्रेडिंग की प्रमुख अवधारणाओं का विश्लेषण करेंगे, जिसमें गोरूटीन, चैनल, म्यूटेक्स और वेट ग्रुप शामिल हैं, साथ ही कोड के व्यावहारिक उदाहरण भी दिए जाएंगे।
1. गोरूटीन: Go के हल्के थ्रेड
गोरूटीन (goroutine) एक फंक्शन है जो समान एड्रेस स्पेस में अन्य फंक्शन के साथ समवर्ती रूप से निष्पादित होता है। यह सिस्टम थ्रेड के ऊपर काम करता है, लेकिन अपने स्वयं के Go शेड्यूलर का उपयोग करता है, जो इसे सामान्य OS थ्रेड की तुलना में काफी सस्ता बनाता है। गोरूटीन का निर्माण go कीवर्ड के साथ होता है।
package main
import ( "fmt" "time")
func say(s string) { for i := 0; i < 5; i++ { time.Sleep(100 * time.Millisecond) fmt.Println(s) }}
func main() { go say("Hello") // गोरूटीन शुरू करना say("World") // मुख्य थ्रेड में सामान्य कॉल}इस उदाहरण में, say("Hello") एक अलग गोरूटीन में निष्पादित होता है, और say("World") मुख्य गोरूटीन में। आउटपुट मिश्रित होगा, क्योंकि दोनों फंक्शन समवर्ती रूप से काम करते हैं। यह याद रखना महत्वपूर्ण है: यदि मुख्य फंक्शन main समाप्त हो जाता है, तो सभी गोरूटीन को जबरन रोक दिया जाएगा।
2. चैनल: गोरूटीन के बीच सुरक्षित डेटा ट्रांसफर
चैनल (channels) टाइप किए गए "पाइप" हैं जिनके माध्यम से गोरूटीन एक दूसरे के साथ संवाद करते हैं। वे स्पष्ट रूप से म्यूटेक्स का उपयोग किए बिना सिंक्रोनाइज़ेशन सुनिश्चित करते हैं। चैनल बफ़र किए हुए (क्षमता के साथ) और बिना बफ़र वाले (सिंक्रोनस) हो सकते हैं।
बिना बफ़र वाला चैनल
package main
import "fmt"
func sum(s []int, c chan int) { total := 0 for _, v := range s { total += v } c <- total // परिणाम चैनल में भेजना}
func main() { s := []int{7, 2, 8, -9, 4, 0} c := make(chan int)
go sum(s[:len(s)/2], c) go sum(s[len(s)/2:], c)
x, y := <-c, <-c // चैनल से प्राप्त करना
fmt.Println(x, y, x+y)}यहाँ दो गोरूटीन ऐरे के आधे भागों का योग निकालती हैं और परिणाम चैनल में भेजती हैं। मुख्य गोरूटीन दोनों मान प्राप्त होने तक ब्लॉक रहती है। बिना बफ़र वाला चैनल एक सिंक्रोनस पॉइंट की तरह काम करता है: भेजना तब तक ब्लॉक रहता है जब तक प्राप्तकर्ता तैयार न हो, और इसके विपरीत।
बफ़र किया हुआ चैनल
package main
import "fmt"
func main() { ch := make(chan int, 2) // 2 एलिमेंट का बफ़र ch <- 1 ch <- 2 // ch <- 3 // यह deadlock का कारण बनेगा, क्योंकि बफ़र भरा है fmt.Println(<-ch) fmt.Println(<-ch)}बफ़र किया हुआ चैनल बिना ब्लॉकिंग के डेटा भेजने की अनुमति देता है, जब तक बफ़र भर न जाए। यह तब सुविधाजनक होता है जब भेजने की गति प्रोसेसिंग की गति से अधिक हो।
3. सिंक्रोनाइज़ेशन: WaitGroup और म्यूटेक्स
हालाँकि चैनल अधिकांश परिदृश्यों को कवर करते हैं, कभी-कभी सिंक्रोनाइज़ेशन पर अधिक सूक्ष्म नियंत्रण की आवश्यकता होती है। इसके लिए sync पैकेज में WaitGroup (गोरूटीन के समूह के पूरा होने की प्रतीक्षा करना) और Mutex (साझा डेटा की सुरक्षा के लिए परस्पर अपवर्जन) उपलब्ध हैं।
WaitGroup: सभी गोरूटीन की प्रतीक्षा करना
package main
import ( "fmt" "sync")
func worker(id int, wg *sync.WaitGroup) { defer wg.Done() // समाप्त होने पर काउंटर घटाएँ fmt.Printf("Worker %d starting", id) // कार्य का अनुकरण fmt.Printf("Worker %d done", id)}
func main() { var wg sync.WaitGroup
for i := 1; i <= 3; i++ { wg.Add(1) // काउंटर बढ़ाएँ
```