通道概念
通道(channel) ,就是一个管道,可以想像成 Go 协程之间通信的管道。它是一种队列式的数据结构,遵循先入先出的规则。
通道的声明
每个通道都只能传递一种数据类型的数据,在你声明的时候,我们要指定通道的类型。chan Type 表示 Type 类型的通道。通道的零值为 nil 。
var 通道名 chan 通道类型
通道的初始化
声明完通道后,通道的值为 nil ,我们不能直接使用,必须先使用 make 函数对通道进行初始化操作。
通道名 = make(chan 通道类型)
或者使用短申明一次到位ch := make(chan string)
使用通道发送和接收数据
往通道发送数据:通道名 <- data
往通道接受数据:value := <- 通道名
通道旁的箭头方向指定了是发送数据还是接收数据。箭头指向通道,代表数据写入到通道中;箭头往通道指向外,代表从通道读数据出去。
注意: 发送与接收默认是阻塞的
如果从通道接收数据没接收完主协程是不会继续执行下去的。当把数据发送到通道时,会在发送数据的语句处发生阻塞,直到有其它协程从通道读取到数据,才会解除阻塞。与此类似,当读取通道的数据时,如果没有其它的协程把数据写入到这个通道,那么读取过程就会一直阻塞着。
通道的关闭
对于一个已经使用完毕的通道,我们要将其进行关闭。close(channel_name)
这里要注意,对于一个已经关闭的通道如果再次关闭会导致报错,我们可以在接收数据时,判断通道是否已经关闭,从通道读取数据返回的第二个值表示通道是否没被关闭,如果已经关闭,返回值为 false ;如果还未关闭,返回值为 true 。`value, ok := <- channel_name
通道的容量与长度
我们在前面讲过 make 函数是可以接收两个参数的,同理,创建通道可以传入第二个参数——容量。
- 当容量为 0 时,说明通道中不能存放数据,在发送数据时,必须要求立马有人接收,否则会报错。此时的通道称之为无缓冲通道。
- 当容量为 1 时,说明通道只能缓存一个数据,若通道中已有一个数据,此时再往里发送数据,会造成程序阻塞。利用这点可以利用通道来做锁。
- 当容量大于 1 时,通道中可以存放多个数据,可以用于多个协程之间的通信管道,共享资源。
既然通道有容量和长度,那么我们可以通过 cap 函数和 len 函数获取通道的容量和长度。
package main
import (
"fmt"
)
func main() {
// 创建一个通道
c := make(chan int, 3)
fmt.Println("初始化后:")
fmt.Println("cap =", cap(c))
fmt.Println("len =", len<