当前位置:网站首页>Detailed instructions for channels

Detailed instructions for channels

2022-06-21 12:10:00 attempt_ to_ do

goroutine Run in the same address space , So access to shared memory must be synchronized . that goroutine How to communicate data between ,Go It provides a good communication mechanism channel.channel It can be done with Unix shell The two-way pipeline in the : It can send or receive values . These values can only be of a specific type :channel type . Define a channel when , Also need definition to send to channel The type of value of . Be careful , You have to use make establish channel:

ci := make(chan int)
cs := make(chan string)
cf := make(chan interface{
    })

channel By the operator <- To receive and send data

ch <- v    //  send out v To channel ch.
v := <-ch  //  from ch Data received in , And assign it to v

package main
import "fmt"
func sum(a []int, c chan int) {
    
    total := 0
    for _, v := range a {
    
        total += v
    }
    c <- total  // send total to c
}
func main() {
    
    a := []int{
    7, 2, 8, -9, 4, 0}
    c := make(chan int)
    go sum(a[:len(a)/2], c)
    go sum(a[len(a)/2:], c)
    x, y := <-c, <-c  // receive from c
    fmt.Println(x, y, x + y)
}

By default ,channel Both receiving and sending data are blocked , Unless the other end is ready , So that makes Goroutines Synchronization becomes more simple , Without explicit lock. So called blocking , That is, if you read (value := <-ch) It will be blocked , Until data is received . secondly , Any sending (ch<-5) Will be blocked , Until the data is read . No buffer channel It's in multiple goroutine Great tools for syncing between .

Buffered Channels

Above we introduced the default non cache type channel, however Go It is also allowed to specify channel The buffer size of , It's simple , Namely channel How many elements can be stored .ch:= make(chan bool, 4), Created to store 4 An element of bool type channel. In this channel in , front 4 Elements can be written without blocking . When writing the 5 Element time , The code will block , Until something else goroutine from channel Read some elements , Make room .

ch := make(chan type, value)

When value = 0 when ,channel It's read and write without buffer , When value > 0 when ,channel There's a cushion 、 It's non blocking , Until writing is full. value Only elements block writing .

Range and Close

Go adopt range, Like operation slice perhaps map Same operation cache type channel.


package main
import (
    "fmt"
)
func fibonacci(n int, c chan int) {
    
    x, y := 1, 1
    for i := 0; i < n; i++ {
    
        c <- x
        x, y = y, x + y
    }
    close(c)
}
func main() {
    
    c := make(chan int, 10)
    go fibonacci(cap(c), c)
    for i := range c {
    
        fmt.Println(i)
    }
}

for i := range c Be able to read continuously channel The data in it , Until it's time to channel Is explicitly turned off . In the above code, we can see that it can be closed explicitly channel, Producers use built-in functions close close channel. close channel After that, no more data can be sent , In the consumer side you can use grammar v, ok := <-ch test channel Is it closed . If ok return false, It means that channel There is no data and it has been shut down .

Select

What we mentioned above is that there is only one channel The situation of , So if there are multiple channel When , How can we operate ,Go It provides a keyword select, adopt select Can monitor channel Data flow on .

select The default is blocked , Only when the monitor channel Only run when there is a send or receive available in , When more than one channel When it's all ready ,select It's a random choice to execute .


package main
import "fmt"
func fibonacci(c, quit chan int) {
    
    x, y := 1, 1
    for {
    
        select {
    
        case c <- x:
            x, y = y, x + y
        case <-quit:
            fmt.Println("quit")
            return
        }
    }
}
func main() {
    
    c := make(chan int)
    quit := make(chan int)
    go func() {
    
        for i := 0; i < 10; i++ {
    
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

stay select There are also default grammar ,select In fact, it's similar switch The function of ,default It's for monitoring channel When you're not ready , Default execution (select Wait no longer blocked channel).


select {
    
case i := <-c:
    // use i
default:
    //  When c When it's blocked, execute here 
}

Overtime

Sometimes there will be goroutine Blocking condition , So how can we prevent the whole program from blocking ? We can use select To set the timeout , This is achieved by :


func main() {
    
    c := make(chan int)
    o := make(chan bool)
    go func() {
    
        for {
    
            select {
    
                case v := <- c:
                    println(v)
                case <- time.After(5 * time.Second):
                    println("timeout")
                    o <- true
                    break
            }
        }
    }()
    <- o
}
原网站

版权声明
本文为[attempt_ to_ do]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/172/202206211159571543.html