channel 提供了一种通信机制,通过它,一个 goroutine 可以想另一 goroutine 发送消息。channel 本身还需关联了一个类型,也就是 channel 可以发送数据的类型。例如: 发送 int 类型消息的 channel 写作 chan int 。

说明

  1. channel是引用类型,必须初始化
  2. 初始化是通过make初始化的
  3. 总结:make初始化三种类型:slice, map和channel

    1. 申明

    1. var msg chan int

    2. 初始化和关闭

    1. msg = make(chan int) #不带缓冲区
    2. msg = make(chan int, 16) #带缓冲区

    3. 放数据和取数据

    ```go package main

import “fmt”

func main(){ var msg chan int msg = make(chan int, 1) msg<- 1 data := <- msg fmt.Println(data) }

v, ok := <-ch #它可以用来检查Channel是否已经被关闭了。

  1. <a name="fAGsh"></a>
  2. ## 4. 一个经典错误
  3. ```go
  4. package main
  5. import "fmt"
  6. func main(){
  7. var msg chan int
  8. msg = make(chan int)
  9. msg<- 1
  10. data := <- msg
  11. fmt.Println(data)
  12. }

5. 通过启动协程消费channel

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. func main(){
  7. var msg chan int
  8. msg = make(chan int)
  9. go func(){
  10. data := <- msg
  11. fmt.Println(data)
  12. }()
  13. msg <- 1 #试试把这一行写到11行之后看看
  14. }

6. 通过for range获取channel的数据

range c产生的迭代值为Channel中发送的值,它会一直迭代直到channel被关闭。上面的例子中如果把close(c)注释掉,程序会一直阻塞在for …… range那一行。

  1. func main() {
  2. go func() {
  3. time.Sleep(1 * time.Hour)
  4. }()
  5. c := make(chan int)
  6. go func() {
  7. for i := 0; i < 10; i = i + 1 {
  8. c <- i
  9. }
  10. close(c)
  11. }()
  12. for i := range c {
  13. fmt.Println(i)
  14. }
  15. fmt.Println("Finished")
  16. }

7. 关闭

内建的close方法可以用来关闭channel。
总结一下channel关闭后sender的receiver操作。
如果channel c已经被关闭,继续往它发送数据会导致panic: send on closed channel:

  1. import "time"
  2. func main() {
  3. go func() {
  4. time.Sleep(time.Hour)
  5. }()
  6. c := make(chan int, 10)
  7. c <- 1
  8. c <- 2
  9. close(c)
  10. c <- 3
  11. }

但是从这个关闭的channel中不但可以读取出已发送的数据,还可以不断的读取零值:

  1. c := make(chan int, 10)
  2. c <- 1
  3. c <- 2
  4. close(c)
  5. fmt.Println(<-c) //1
  6. fmt.Println(<-c) //2
  7. fmt.Println(<-c) //0
  8. fmt.Println(<-c) //0

但是如果通过range读取,channel关闭后for循环会跳出:

  1. c := make(chan int, 10)
  2. c <- 1
  3. c <- 2
  4. close(c)
  5. for i := range c {
  6. fmt.Println(i)
  7. }

通过i, ok := <-c可以查看Channel的状态,判断值是零值还是正常读取的值。

  1. c := make(chan int, 10)
  2. close(c)
  3. i, ok := <-c
  4. fmt.Printf("%d, %t", i, ok) //0, false

channel可以用在goroutine之间的同步。
下面的例子中main goroutine通过done channel等待worker完成任务。 worker做完任务后只需往channel发送一个数据就可以通知main goroutine任务完成。