खोज…
परिचय
गो में, कोऑर्डिनेट गोरोइन के उपयोग के माध्यम से प्राप्त किया जाता है, और गोरोइन के बीच संचार आमतौर पर चैनलों के साथ किया जाता है। हालांकि, सिंक्रनाइज़ेशन के अन्य साधन, जैसे म्यूटेक्स और प्रतीक्षा समूह उपलब्ध हैं, और जब भी वे चैनलों की तुलना में अधिक सुविधाजनक होते हैं, तब उनका उपयोग किया जाना चाहिए।
वाक्य - विन्यास
- do doork () // फंक्शन doWork को goroutine के रूप में चलाएं
- ch: = make (chan int) // घोषित नए चैनल का प्रकार int
- ch <- 1 // एक चैनल पर भेज रहा है
- एक चैनल से मूल्य = <-ch // प्राप्त करना
टिप्पणियों
गोआटाइन्स इन गो उपयोग के मामले में अन्य भाषाओं के धागे के समान है। आंतरिक रूप से, गो कई थ्रेड बनाता है ( GOMAXPROCS
द्वारा निर्दिष्ट) और फिर थ्रेड पर चलने के लिए गोरूटीन्स को शेड्यूल करता है। इस डिज़ाइन के कारण, मेमोरी के उपयोग और आरंभीकरण समय के संदर्भ में थ्रेड्स की तुलना में गो के कंज़ेम्पर मैकेनिज़्म बहुत अधिक कुशल हैं।
गोरोचन बनाना
किसी भी समारोह कीवर्ड के साथ अपने मंगलाचरण लगाकर द्वारा एक goroutine के रूप में लागू किया जा सकता है go
:
func DoMultiply(x,y int) {
// Simulate some hard work
time.Sleep(time.Second * 1)
fmt.Printf("Result: %d\n", x * y)
}
go DoMultiply(1,2) // first execution, non-blocking
go DoMultiply(3,4) // second execution, also non-blocking
// Results are printed after a single second only,
// not 2 seconds because they execute concurrently:
// Result: 2
// Result: 12
ध्यान दें कि फ़ंक्शन का रिटर्न मान अनदेखा किया गया है।
नमस्ते विश्व गोरौते
एकल चैनल, एकल गोरोइन, एक लिखना, एक पढ़ना।
package main
import "fmt"
import "time"
func main() {
// create new channel of type string
ch := make(chan string)
// start new anonymous goroutine
go func() {
time.Sleep(time.Second)
// send "Hello World" to channel
ch <- "Hello World"
}()
// read from channel
msg, ok := <-ch
fmt.Printf("msg='%s', ok='%v'\n", msg, ok)
}
चैनल ch
एक असंबद्ध या तुल्यकालिक चैनल है ।
समय time.Sleep
है। यहां main()
फ़ंक्शन का वर्णन करने के लिए ch
चैनल पर प्रतीक्षा की जाएगी, जिसका मतलब है कि फ़ंक्शन शाब्दिक जिसे गोरोइन के रूप में निष्पादित किया गया है, उस चैनल के माध्यम से मान भेजने का समय है: प्राप्त ऑपरेटर <-ch
निष्पादन को रोक देगा। main()
। यदि ऐसा नहीं होता है, तो main()
बाहर निकलने पर गोरोइन को मार दिया जाएगा, और इसके मूल्य को भेजने का समय नहीं होगा।
गोरक्षकों का इंतजार
जब main
कार्य समाप्त होता है , तो कार्यक्रम समाप्त हो जाते हैं , इसलिए सभी गोरआउट के समाप्त होने की प्रतीक्षा करना आम बात है। इसके लिए एक सामान्य समाधान है सिंक .aitGroup ऑब्जेक्ट का उपयोग करना।
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup // 1
func routine(i int) {
defer wg.Done() // 3
fmt.Printf("routine %v finished\n", i)
}
func main() {
wg.Add(10) // 2
for i := 0; i < 10; i++ {
go routine(i) // *
}
wg.Wait() // 4
fmt.Println("main finished")
}
निष्पादन के क्रम में WaitGroup उपयोग:
- वैश्विक चर की घोषणा। इसे वैश्विक बनाना सभी कार्यों और विधियों के लिए सबसे आसान तरीका है।
- काउंटर बढ़ाना। यह मुख्य गोरोइनटाइन में किया जाना चाहिए क्योंकि इस बात की कोई गारंटी नहीं है कि स्मृति मॉडल की गारंटी के कारण एक नया शुरू किया गया गोरोइन 4 से पहले निष्पादित होगा।
- काउंटर कम करना। यह एक गोरोइन के बाहर निकलने पर किया जाना चाहिए। एक आस्थगित कॉल का उपयोग करके, हम यह सुनिश्चित करते हैं कि जब भी कार्य समाप्त होता है , तब इसे कॉल किया जाएगा , फिर चाहे वह कैसे भी समाप्त हो।
- काउंटर तक पहुंचने का इंतजार 0. यह मुख्य गोरोइनटाइन में किया जाना चाहिए ताकि कार्यक्रम को बाहर निकलने से पहले ही रोका जा सके कि सभी गोरआउट समाप्त हो चुके हैं।
* नए गोरआउट शुरू करने से पहले पैरामीटर का मूल्यांकन किया जाता है । इस प्रकार wg.Add(10)
से पहले उनके मूल्यों को स्पष्ट रूप से परिभाषित करना आवश्यक है, ताकि संभवतः- wg.Add(10)
काउंटर में वृद्धि न हो। WaitGroup में 10 आइटम जोड़ रहा है, इसलिए यह wg.Wait
से पहले 10 आइटम्स की प्रतीक्षा करेगा। main()
गोरोइन पर नियंत्रण वापस करता है। यहाँ, लूप के लिए i का मान परिभाषित किया गया है।
एक लूप में गोरोइटिन के साथ क्लोजर का उपयोग करना
जब एक लूप में, निम्न उदाहरण में लूप वेरिएबल (वैल) एक एकल वैरिएबल होता है जो लूप के ऊपर जाते ही मान बदल देता है। इसलिए किसी को वास्तव में गोरोइन के लिए मूल्यों की प्रत्येक घाटी को पारित करने के लिए निम्नलिखित करना चाहिए:
for val := range values {
go func(val interface{}) {
fmt.Println(val)
}(val)
}
आपको बस इतना करना हो तो बस जाते हो func(val interface{}) { ... }()
वैल गुजर बिना, तो का मान val
हो जाएगा जो कुछ भी वैल है जब goroutines वास्तव में चलाता है।
समान प्रभाव प्राप्त करने का दूसरा तरीका है:
for val := range values {
val := val
go func() {
fmt.Println(val)
}()
}
अजीब दिखने वाली val := val
प्रत्येक पुनरावृत्ति में एक नया चर बनाता है, जो तब गोरोइन द्वारा एक्सेस किया जाता है।
गोरोचन को रोकना
package main
import (
"log"
"sync"
"time"
)
func main() {
// The WaitGroup lets the main goroutine wait for all other goroutines
// to terminate. However, this is no implicit in Go. The WaitGroup must
// be explicitely incremented prior to the execution of any goroutine
// (i.e. before the `go` keyword) and it must be decremented by calling
// wg.Done() at the end of every goroutine (typically via the `defer` keyword).
wg := sync.WaitGroup{}
// The stop channel is an unbuffered channel that is closed when the main
// thread wants all other goroutines to terminate (there is no way to
// interrupt another goroutine in Go). Each goroutine must multiplex its
// work with the stop channel to guarantee liveness.
stopCh := make(chan struct{})
for i := 0; i < 5; i++ {
// It is important that the WaitGroup is incremented before we start
// the goroutine (and not within the goroutine) because the scheduler
// makes no guarantee that the goroutine starts execution prior to
// the main goroutine calling wg.Wait().
wg.Add(1)
go func(i int, stopCh <-chan struct{}) {
// The defer keyword guarantees that the WaitGroup count is
// decremented when the goroutine exits.
defer wg.Done()
log.Printf("started goroutine %d", i)
select {
// Since we never send empty structs on this channel we can
// take the return of a receive on the channel to mean that the
// channel has been closed (recall that receive never blocks on
// closed channels).
case <-stopCh:
log.Printf("stopped goroutine %d", i)
}
}(i, stopCh)
}
time.Sleep(time.Second * 5)
close(stopCh)
log.Printf("stopping goroutines")
wg.Wait()
log.Printf("all goroutines stopped")
}
पिंग पोंग दो गोरोइटिन के साथ
package main
import (
"fmt"
"time"
)
// The pinger prints a ping and waits for a pong
func pinger(pinger <-chan int, ponger chan<- int) {
for {
<-pinger
fmt.Println("ping")
time.Sleep(time.Second)
ponger <- 1
}
}
// The ponger prints a pong and waits for a ping
func ponger(pinger chan<- int, ponger <-chan int) {
for {
<-ponger
fmt.Println("pong")
time.Sleep(time.Second)
pinger <- 1
}
}
func main() {
ping := make(chan int)
pong := make(chan int)
go pinger(ping, pong)
go ponger(ping, pong)
// The main goroutine starts the ping/pong by sending into the ping channel
ping <- 1
for {
// Block the main thread until an interrupt
time.Sleep(time.Second)
}
}
गो प्लेग्राउंड में इस कोड का थोड़ा संशोधित संस्करण चलाएं