美文网首页
golang之channels

golang之channels

作者: 10xjzheng | 来源:发表于2019-10-14 17:57 被阅读0次

    以下是web application with golang 书里的笔记。

    1.channels 和 Buffered Channels

    • channels
      channel是goroutine之间通信的一种机制。
      定义方式如下:
    ci := make(chan int)
    cs := make(chan string)
    
    • Buffered Channels
      channel 还可以定义缓冲区大小,比如:
     ci := make(chan int, 2)
    
    • 存取数据
      使用<-来存入/获取数据,箭头方向代表数据的流向。
      比如
      向channel ci 写入数据: ci <- 10
      从channel ci 获取数据并赋值到num:num := <- ci

    2.Range和Close

    channels里面的数据可以用range来读,但是这里有需要注意的地方:
    1.记住应该在生产者的地方关闭channel,而不是消费的地方去关闭它,这样容易引起panic
    2.另外记住一点的就是channel不像文件之类的,不需要经常去关闭,只有当你确实没有任何发送数据了,或者你想显式的结束range循环之类的。如果没关闭,会报错:fatal error: all goroutines are asleep - deadlock!

    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)
        }
    }
    

    3.Select

    如果存在多个channel的时候,我们该如何操作呢,Go里面提供了一个关键字select,通过select可以监听channel上的数据流动。
    select默认是阻塞的,只有当监听的channel中有发送或接收可以进行时才会运行,当多个channel都准备好的时候,select是随机的选择一个执行的。

    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)
    }
    

    在select里面还有default语法,select其实就是类似switch的功能,default就是当监听的channel都没有准备好的时候,默认执行的(select不再阻塞等待channel)。
    有时候会出现goroutine阻塞的情况,那么我们如何避免整个程序进入阻塞的情况呢?我们可以利用select来设置超时,通过如下的方式实现:

    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
    }
    

    相关文章

      网友评论

          本文标题:golang之channels

          本文链接:https://www.haomeiwen.com/subject/yurrmctx.html