खोज…
परिचय
एक चैनल में दिए गए प्रकार के मान होते हैं। मान किसी चैनल को लिखे जा सकते हैं और उससे पढ़े जा सकते हैं, और वे चैनल के अंदर पहले-पहले क्रम में प्रसारित होते हैं। बफ़र्ड चैनलों के बीच एक अंतर है, जिसमें कई संदेश हो सकते हैं, और असंबद्ध चैनल, जो नहीं कर सकते हैं। चैनल आमतौर पर गोरोइनटिस के बीच संवाद करने के लिए उपयोग किए जाते हैं, लेकिन अन्य परिस्थितियों में भी उपयोगी होते हैं।
वाक्य - विन्यास
- make (chan int) // एक अनवांटेड चैनल बनाएं
- make (chan int, 5) // 5 की क्षमता वाला एक बफ़र्ड चैनल बनाएं
- करीब (ch) // एक चैनल "ch" को बंद करता है
- ch <- 1 // एक चैनल "ch" के लिए 1 का मान लिखें
- वैल: = <-ch // चैनल "ch" से एक मान पढ़ें
- वैल, ओके: = <-ch // वैकल्पिक वाक्य रचना; यदि चैनल बंद है तो ओके एक बूल संकेत करता है
टिप्पणियों
खाली स्ट्रक्चर make(chan struct{})
धारण करने वाला चैनल उपयोगकर्ता के लिए एक स्पष्ट संदेश है कि चैनल पर कोई भी जानकारी प्रसारित नहीं की जाती है और यह पूरी तरह से सिंक्रनाइज़ेशन के लिए उपयोग किया जाता है।
असंबद्ध चैनलों के संबंध में, एक चैनल लिखना तब तक ब्लॉक रहेगा जब तक कि एक अन्य गोरोइटिन से एक संबंधित रीड नहीं होता। एक लेखक के इंतजार में अवरुद्ध एक चैनल के लिए भी यही सच है।
सीमा का उपयोग करना
किसी चैनल से कई मान पढ़ते समय, range
का उपयोग करना एक सामान्य पैटर्न है:
func foo() chan int {
ch := make(chan int)
go func() {
ch <- 1
ch <- 2
ch <- 3
close(ch)
}()
return ch
}
func main() {
for n := range foo() {
fmt.Println(n)
}
fmt.Println("channel is now closed")
}
उत्पादन
1
2
3
channel is now closed
समय समाप्ति
चैनल का उपयोग अक्सर टाइमआउट को लागू करने के लिए किया जाता है।
func main() {
// Create a buffered channel to prevent a goroutine leak. The buffer
// ensures that the goroutine below can eventually terminate, even if
// the timeout is met. Without the buffer, the send on the channel
// blocks forever, waiting for a read that will never happen, and the
// goroutine is leaked.
ch := make(chan struct{}, 1)
go func() {
time.Sleep(10 * time.Second)
ch <- struct{}{}
}()
select {
case <-ch:
// Work completed before timeout.
case <-time.After(1 * time.Second):
// Work was not completed after 1 second.
}
}
गोरोचन का समन्वय करना
एक दो चरण प्रक्रिया के साथ एक गोरोइन की कल्पना करें, जहां मुख्य सूत्र को प्रत्येक चरण के बीच कुछ काम करने की आवश्यकता होती है:
func main() {
ch := make(chan struct{})
go func() {
// Wait for main thread's signal to begin step one
<-ch
// Perform work
time.Sleep(1 * time.Second)
// Signal to main thread that step one has completed
ch <- struct{}{}
// Wait for main thread's signal to begin step two
<-ch
// Perform work
time.Sleep(1 * time.Second)
// Signal to main thread that work has completed
ch <- struct{}{}
}()
// Notify goroutine that step one can begin
ch <- struct{}{}
// Wait for notification from goroutine that step one has completed
<-ch
// Perform some work before we notify
// the goroutine that step two can begin
time.Sleep(1 * time.Second)
// Notify goroutine that step two can begin
ch <- struct{}{}
// Wait for notification from goroutine that step two has completed
<-ch
}
बफर बनाम असंबद्ध
func bufferedUnbufferedExample(buffered bool) {
// We'll declare the channel, and we'll make it buffered or
// unbuffered depending on the parameter `buffered` passed
// to this function.
var ch chan int
if buffered {
ch = make(chan int, 3)
} else {
ch = make(chan int)
}
// We'll start a goroutine, which will emulate a webserver
// receiving tasks to do every 25ms.
go func() {
for i := 0; i < 7; i++ {
// If the channel is buffered, then while there's an empty
// "slot" in the channel, sending to it will not be a
// blocking operation. If the channel is full, however, we'll
// have to wait until a "slot" frees up.
// If the channel is unbuffered, sending will block until
// there's a receiver ready to take the value. This is great
// for goroutine synchronization, not so much for queueing
// tasks for instance in a webserver, as the request will
// hang until the worker is ready to take our task.
fmt.Println(">", "Sending", i, "...")
ch <- i
fmt.Println(">", i, "sent!")
time.Sleep(25 * time.Millisecond)
}
// We'll close the channel, so that the range over channel
// below can terminate.
close(ch)
}()
for i := range ch {
// For each task sent on the channel, we would perform some
// task. In this case, we will assume the job is to
// "sleep 100ms".
fmt.Println("<", i, "received, performing 100ms job")
time.Sleep(100 * time.Millisecond)
fmt.Println("<", i, "job done")
}
}
चैनलों को अवरुद्ध और अनब्लॉक करना
डिफ़ॉल्ट रूप से चैंसेल पर संचार सिंक है; जब आप कुछ मूल्य भेजते हैं तो एक रिसीवर होना चाहिए। अन्यथा आपको fatal error: all goroutines are asleep - deadlock!
निम्नलिखित नुसार:
package main
import "fmt"
func main() {
msg := make(chan string)
msg <- "Hey There"
go func() {
fmt.Println(<-msg)
}()
}
बू एक समाधान का उपयोग है: बफ़र्ड चैनलों का उपयोग करें:
package main
import "fmt"
import "time"
func main() {
msg :=make(chan string, 1)
msg <- "Hey There!"
go func() {
fmt.Println(<-msg)
}()
time.Sleep(time.Second * 1)
}
काम खत्म होने का इंतजार है
चैनलों का उपयोग करने के लिए एक आम तकनीक चैनल से पढ़ने के लिए कुछ संख्या में श्रमिकों (या उपभोक्ताओं) का निर्माण करना है। एक सिंक का उपयोग करना। व्हाटग्रुप उन श्रमिकों के चलने का इंतजार करने का एक आसान तरीका है।
package main
import (
"fmt"
"sync"
"time"
)
func main() {
numPiecesOfWork := 20
numWorkers := 5
workCh := make(chan int)
wg := &sync.WaitGroup{}
// Start workers
wg.Add(numWorkers)
for i := 0; i < numWorkers; i++ {
go worker(workCh, wg)
}
// Send work
for i := 0; i < numPiecesOfWork; i++ {
work := i % 10 // invent some work
workCh <- work
}
// Tell workers that no more work is coming
close(workCh)
// Wait for workers to finish
wg.Wait()
fmt.Println("done")
}
func worker(workCh <-chan int, wg *sync.WaitGroup) {
defer wg.Done() // will call wg.Done() right before returning
for work := range workCh { // will wait for work until workCh is closed
doWork(work)
}
}
func doWork(work int) {
time.Sleep(time.Duration(work) * time.Millisecond)
fmt.Println("slept for", work, "milliseconds")
}