1 गोरूटीन का परिचय
1.1 समकालिकता और पैरललिज्म की मौलिक अवधारणाएँ
समकालिकता और पैरललिज्म, ये दो सामान्य अवधारणाएँ हैं जो बहु-सूत्री नमूने प्रोग्रामिंग में प्रयोग होती हैं। इनका उपयोग ईवेंट या प्रोग्राम क्रियाकलाप को समानकालिक रूप से घटित हो सकने की स्थितियों का वर्णन करने के लिए किया जाता है।
- समकालिकता एक ही समय-अवधि में कई कार्यों को प्रसंस्कृत करने का संकेत देती है, परन्तु केवल एक कार्य को हर दिए गए समय पर निर्वाहित किया जाता है। अत्यंत शीघ्रता से वे एक दूसरे के बीच स्पष्ट होकर बदलते रहते हैं, जो उपयोगकर्ता को समकालिक निर्वाह का भ्रांति देता है। समकालिकता एकल-कोर प्रोसेसर्स के लिए उपयुक्त होती है।
- पैरललिज्म वास्तव में कई कार्य सचमुच समान समय पर निर्वाहित होते हैं, जो बहु-कोर प्रोसेसर्स के समर्थन की आवश्यकता होती है।
गो भाषा, समकालिकता को एक प्राथमिक लक्ष्य के रूप में ध्यान में रखकर डिज़ाइन की गई है। यह गोरूटींस और चैनल्स के माध्यम से कुशल समकालिक प्रोग्रामिंग मॉडेल को प्राप्त करती है। गो का रनटाइम गोरूटींस को प्रबंधित करता है, और इन गोरूटींस को मल्टीपल सिस्टम थ्रेड्स पर अनुसूचित कर सकता है कि वे समान समय पर प्रसंस्कृत हो।
1.2 गो भाषा में गोरूटीन्स
गोरूटींस गो भाषा में समकालिक प्रोग्रामिंग को प्राप्त करने के लिए मौलिक अवधारणा हैं। वे गो के रनटाइम द्वारा प्रबंधित हल्के-से-हल्के थ्रेड्स होते हैं। एक उपयोगकर्ता के दृष्टिकोण से, वे थ्रेड्स के लिए उपमा हैं, लेकिन कम संसाधन खपना करते हैं और अधिक तेजी से शुरू होते हैं।
गोरूटीन्स की विशेषताएँ शामिल हैं:
- हल्के-वजान: गोरूटींस पारंपरिक थ्रेड्स की तुलना में कम स्टैक मेमोरी का कब्ज़ा करते हैं, और उनका स्टैक साइज आवश्यकता के हिसाब से विस्तृत या छोटा हो सकता है।
- कम ओवरहेड: गोरूटींस को बनाने और नष्ट करने का अधिकार पारंपरिक थ्रेड्स की तुलना में बहुत कम है।
- सरल संचार तंत्र: चैनल्स गोरूटींस के बीच एक सरल और प्रभावी संचार तंत्र प्रदान करते हैं।
- गैर-अवरोधी डिज़ाइन: कुछ क्रियाओं में गोरूटींस बाकी गोरूटीनस को प्रभावित नहीं करते हैं। उदाहरण के लिए, जब एक गोरूटीन आई/ओ क्रियाओं के लिए प्रतीक्षा कर रही हो, तो अन्य गोरूटींस क्रियान्वित रह सकते हैं।
2 गोरूटीन्स बनाना और प्रबंधन करना
2.1 गोरूटीन कैसे बनाएँ
गो भाषा में, आप go
कीवर्ड का उपयोग करके आसानी से एक गोरूटीन बना सकते हैं। जब आप किसी फ़ंक्शन को go
कीवर्ड के साथ जोड़ते हैं, तो वह फ़ंक्शन एक नई गोरूटीन में बरकरार होकर वास्तविक समय में निर्वाहित होगा।
आइए एक सरल उदाहरण देखें:
package main
import (
"fmt"
"time"
)
// स्वागत कहने के लिए एक फ़ंक्शन का परिभाषित करें
func sayHello() {
fmt.Println("नमस्ते")
}
func main() {
// `go` कीवर्ड का उपयोग करके एक नई गोरूटीन शुरू करें
go sayHello()
// मुख्य गोरूटीन एक अवधि के लिए प्रतीक्षा करता है ताकि `sayHello` निर्वाहित हो सके
time.Sleep(1 * time.Second)
fmt.Println("मुख्य फ़ंक्शन")
}
उपरोक्त कोड में, sayHello()
फ़ंक्शन एक नई गोरूटीन में आसानी से बरकरार होगा। इसका अर्थ है कि main()
फ़ंक्शन sayHello()
को समाप्त होने की प्रतीक्षा से पहले नहीं करेगा। इसलिए, हम time.Sleep
का उपयोग मुख्य गोरूटीन को रोकने के लिए करते हैं, ताकि sayHello
में प्रिंट करने का कथन निर्वाहित हो सके। यह केवल प्रदर्शन के उद्देश्यों के लिए है। वास्तविक विकास में, हम सामान्यत: अलग-अलग गोरूटीन्स का निर्वाह करने के लिए चैनल्स या अन्य समक्रमण विधियों का उपयोग करते हैं।
नोट: व्यावसायिक अनुप्रयोगों में,
time.Sleep()
का उपयोग एक गोरूटीन को समाप्त होने की प्रतीक्षा करने के लिए नहीं करना चाहिए, क्योंकि यह एक विश्वसनीय समक्षमन विधि नहीं है।
2.2 गोरूटीन अनुसूचिति व्यवस्था
गो में, गोरूटीन्स की अनुसूचना गो के रनटाइम के अनुसूचक द्वारा हैं, जो उपलब्ध तार्किक प्रोसेसर्स पर निर्वाता समय का आवंटन करने के लिए जिम्मेदार होता है। गो अनुसूचक M:N
अनुसूचना तकनीक (बहुत से गोरूटीन्स को बहुत से ओएस थ्रेड्स पर मैप करता है) का उपयोग करता है, ताकि बहु-कोर प्रोसेसर्स पर बेहतर प्रदर्शन प्राप्त कर सके।
GOMAXPROCS और तार्किक प्रोसेसर्स
GOMAXPROCS
एक वातावरणीय मान है जो रनटाइम अनुसूचक को परिभाषित करता है जो रनटाइम अनुसूचक को परिभाषित करता है, जिसकी डिफ़ॉल्ट संख्या मशीन पर कोरों की संख्या होती है। गो रनटाइम प्रत्येक तार्किक प्रोसेसर के लिए एक ओएस थ्रेडास निर्धारित करता है। GOMAXPROCS
को सेट करके, हम रनटाइम द्वारा उपयोगित किए जाने वाले कोरों की संख्या को प्रतिबंधित कर सकते हैं।
import "runtime"
func init() {
runtime.GOMAXPROCS(2)
}
उपरोक्त कोड, जबकि यह प्रोग्राम एक मशीन पर अधिक कोरों के साथ चल रहा हो, तो गोरूटीन्स की अनुसूचना करने के लिए अधिकतम दो कोरों को संरेखित करता है।
स्केड्यूलर ऑपरेशन
स्केड्यूलर तीन महत्वपूर्ण एंटिटी का उपयोग करके कार्य करता है: M (मशीन), P (प्रोसेसर), और G (गोरूटीन)। M मशीन या थ्रेड का प्रतीक करता है, P स्केड्यूलिंग का संदर्भ प्रस्तुत करता है, और G विशिष्ट गोरूटीन का प्रतीक है।
- M: ओएस कर्नल थ्रेड्स के संकेत रूप में काम करने वाली मशीन या थ्रेड का प्रतीक करता है।
- P: हर P में लोकल गोरूटीन कतार होती है जो गोरूटीन को निष्पादित करने के लिए आवश्यक संसाधन को प्रतिनियोजित करता है।
- G: गोरूटीन का प्रतीक है, जिसमें इसकी निष्पादन स्टैक, निर्देशिका सेट, और अन्य जानकारी शामिल है।
गो स्केड्यूलर के कार्यन नियम हैं:
- M के पास G को निष्पादित करने के लिए P होना चाहिए। अगर P नहीं है, तो M को थ्रेड कैश में वापस भेज दिया जाएगा।
- जब G को किसी अन्य G द्वारा ब्लॉक नहीं किया गया है (जैसे कि सिस्टम कॉल में), तो यह M पर संभवत: होंगे, जिससे गोरूटीन के स्थानीय डेटा को अधिक दक्ष CPU कैश उपयोग के लिए 'हॉट' बनाए रखने में मदद मिले।
- जब G ब्लॉक होता है, M और P अलग हो जाएंगे, और P नए M की तलाश करेगा या नए M को जागरूक करेगा ताकि यह अन्य G को सेवा कर सके।
go func() {
fmt.Println("Goroutine से नमस्ते")
}()
ऊपर का कोड नया गोरूटीन शुरू करने का प्रदर्शन करता है, जिससे स्केड्यूलर को इस नए G को निष्पादित करने के लिए कतार में जोड़ने का संकेत मिलता है।
गोरूटीन की अधिकतम समयावधि प्रबंधन
प्रारंभिक चरणों में, गो ने सहकर्मी अनुसूचीबद्धि का उपयोग किया, अर्थात अगर गोरूटीन ने स्वैंके होडिली नियंत्रण से लंबा समय तक निष्पादित होते थे तो वे अन्य गोरूटीन को भूखमरी कर देते थे। अब, गो स्केड्यूलर ने अधिकारी अनुसूचीबद्धि को लागू करना शुरू किया है, जिससे लंबे समय तक चलने वाले G को रोका जा सकता है ताकि अन्य G को निष्पादित करने का मौका मिले।
2.3 गोरूटीन जीवनचक्र प्रबंधन
आपके Go एप्लिकेशन की मजबूती और प्रदर्शन सुनिश्चित करने के लिए, गोरूटीन के जीवनचक्र को समझना और सही ढंग से प्रबंधित करना महत्वपूर्ण है। गोरूटीनों को शुरू करना सरल है, लेकिन सही प्रबंधन के बिना, वे मेमोरी लीक और रेस कंडीशन जैसी समस्याओं का कारण बन सकते हैं।
सुरक्षित रूप से गोरूटीन शुरू करना
गोरूटीन शुरू करने से पहले, सुनिश्चित करें कि इसका कार्यभार और रनटाइम विशेषताएँ समझ ली गई हैं। गोरूटीन के एक साफ शुरू और समाप्ति होनी चाहिए ताकि "गोरूटीन ऑर्पेंट" बनाने से बचा जा सके।
func worker(done chan bool) {
fmt.Println("काम कर रहा हूँ...")
time.Sleep(time.Second) // महंगा कार्य नकारत्मक करने के लिए
fmt.Println("काम समाप्त हो गया।")
done <- true
}
func main() {
// यहां, गो में चैनल योजना का उपयोग किया गया है। आप सधंा सोच सकते हैं कि चैनल को एक बुनियादी संदेश कतार के रूप में सोचें, और "<-"ऑपरेटर का उपयोग करके कतार डेटा का पठन और लेखन करें।
done := make(chan bool, 1)
go worker(done)
// गोरूटीन के समाप्त होने का इंतजार करें
<-done
}
ऊपर का कोड यह दिखाता है की "डन" चैनल का उपयोग करके गोरूटीन के समाप्त होने का इंतजार करने का एक तरीका है।
नोट: इस उदाहरण में गो के चैनल मेकेनिज्म का उपयोग हुआ है, जिसका विवरण बाद के अध्यायों में दिया जाएगा।
गोरूटीन्स को रोकना
सामान्य रूप से, पूरे कार्यक्रम के अंत में सभी गोरूटीन्स स्वत: ही समाप्त हो जाते हैं। हालांकि, लंबे समय तक चलने वाले सेवाओं में, हमें गोरूटीन्स को सक्रिय रूप से बंद करने की आवश्यकता हो सकती है।
- स्टॉप संकेत भेजने के लिए चैनल का उपयोग करें: गोरूटीन्स स्टॉप संकेत के लिए चैनल को जांच सकते हैं।
stop := make(chan struct{})
go func() {
for {
select {
case <-stop:
fmt.Println("स्टॉप संकेत प्राप्त हुआ। बंद कर रहा हूँ...")
return
default:
// सामान्य कार्य को निष्पादित करें
}
}
}()
// स्टॉप संकेत भेजें
stop <- struct{}{}
-
लाइफसाइकल प्रबंधन के लिए
संदर्भ
पैकेज का उपयोग करें:
ctx, cancel := context.WithCancel(context.Background())
go func(ctx context.Context) {
for {
select {
case <-ctx.Done():
fmt.Println("स्टॉप संकेत प्राप्त हुआ। बंद कर रहा हूँ...")
return
default:
// सामान्य कार्य को निष्पादित करें
}
}
}(ctx)
// जब आप गोरूटीन को बंद करना चाहते हैं
cancel()
संदर्भ
पैकेज का उपयोग गोरूटीन के लाइफसाइकल को और अधिक लचीला बनाने के लिए अधिक सहज नियंत्रण प्रदान करता है। बड़े एप्लिकेशन या माइक्रोसर्विसों के लिए, संदर्भ
गोरूटीन जीवनचक्र को नियंत्रित करने का सिफारिश किया जाता है।