信道

什么是信道?

信道可以想像成 Go 协程之间通信的管道。如同管道中的水会从一端流到另一端,通过使用信道,数据也可以从一端发送,在另一端接收。

信道的声明

所有信道都关联了一个类型。信道只能运输这种类型的数据,而运输其他类型的数据都是非法的。

chan T 表示 T 类型的信道。

信道的零值为 nil。信道的零值没有什么用,应该像对 map 和切片所做的那样,用 make 来定义信道。

信道的发送和接收

a <- 1  //表示在a里面放入1
b := <-a  //将a值取出来,赋值给b

发送和接收默认是阻塞的

当把数据发送到信道时,程序控制会在发送数据的语句处发生阻塞,直到有其它 Go 协程从信道读取到数据,才会解除阻塞。与此类似,当读取信道的数据时,如果没有其它的协程把数据写入到这个信道,那么读取过程就会一直阻塞着。

代码示例

package main

import (
    "fmt"
    "time"
)

func test(a chan int){
    fmt.Println("你好啊!")
    //放值
    time.Sleep(time.Second*3)  //睡三秒后再打印b值
    a <- 1  //表示在a里面放入1
}
func main(){
    var a chan int = make(chan int)  //注意:一定要初始化
    go test(a)
    b := <-a  //将a值取出来,赋值给b

    fmt.Println(b)


}

死锁

默认取值和赋值都是阻塞的。当 Go 协程给一个信道发送数据时,照理说会有其他 Go 协程来接收数据。如果没有的话,程序就会在运行时触发 panic,形成死锁。

同理,当有 Go 协程等着从一个信道接收数据时,我们期望其他的 Go 协程会向该信道写入数据,要不然程序就会触发 panic。

package main

func main() {  
    a := make(chan int)
    a <- 5
}

单向信道

func sendData(sendch chan<- int) {  // chan<- int 是只写的,如果读取信道就会报错
    sendch <- 10

}

func main() {
    // 只写信道
    sendch := make(chan int)
    go sendData(sendch)
    fmt.Println(<-sendch)
}

信道关闭

数据发送方可以关闭信道,通知接收方这个信道不再有数据发送过来。

当从信道接收数据时,接收方可以多用一个变量来检查信道是否已经关闭。

package main

import (
    "fmt"
)

func producer(chnl chan int) {
    for i := 0; i < 10; i++ {
        chnl <- i
    }
    close(chnl)
}
func main() {
    ch := make(chan int)
    go producer(ch)
    for {
        v, ok := <-ch
        // 如果信道关闭,ok就是false
        // 如果没关闭,就是true
        if ok == false {
            break
        }
        fmt.Println("Received ", v, ok)
    }
}

通过range循环信道

func producer(chnl chan int) {
    for i := 0; i < 10; i++ {
        chnl <- i
    }
    close(chnl)
}
func main() {
    ch := make(chan int)
    go producer(ch)
    for v := range ch {
        fmt.Println("Received ",v)
    }
}

猜你喜欢

转载自www.cnblogs.com/xiongying4/p/12037037.html