Go goroutine 和 channel 详解 (二) :channel

本系列是阅读 “The Go Programming Language” 理解和记录。

定义

如果说 goroutine 是并发执行的一个 Go program, channel 就是它们之间的连接通道,它提供了 goroutine 之间相互通信的机制。Channel 是有类型的,channel 中使用的 type 称之为 element type,比如 int 类型的 channel 写作为 chan int

Go 使用 make 内建函数创建 channel。

1
ch := make(chan int)

同 map 一样,一个 channel 引用着 make 创建的底层数据结构上,当把 channel 当做函数参数传递时,实际上是拷贝一份 reference,也就是说函数内部和外部引用的是相同的数据结构,所以在函数内部可以直接修改 channel 的值。同其它 reference type 一样,channel 的 zero value 是 nil

Channel 是可比较的

Channel 是可比较的,如果两个 channel 的类型相同,它们可以彼此相互比较

1
2
3
4
5
6
7
ch01 := make(chan int)
ch02 := make(chan int)
if ch01 == ch02 {
fmt.Println("ch01 == ch02")
} else {
fmt.Println("ch01 != ch02")
}

两个不是 nil 的 channel 比较实际上比较的他们的 reference 是否相同,如果他们都引用同一个 channel,则他们相同:

1
2
3
4
5
6
7
8
9
10
func main() {
ch01 := make(chan int)
func02(ch01, ch01)
}

func func02(a chan int, b chan int) {
if a == b {
fmt.Println("a == b")
}
}

当然 channel 也可以和 nil 比较,没有初始化的 channel 就是 nil:

1
2
3
4
var ch02 chan int
if ch02 == nil {
fmt.Println("ch02 is nil")
}

Channel 的基本操作

Channel 有三种基本的操作 send、receive、close。

Send

Channel 支持 send 操作,意思是向 channel 中发送数据,Go 使用 <- 操作符来实现 send:

1
ch <- x //send

Send 时 <- 在 channel 右侧。

Receive

Channel 还支持 receive 操作,意思是从 channel 中取出数据,Go 也是使用 <- 操作符来实现 receive:

1
x := <- ch //receive

Receive 时 <- 在左侧,如果一个执行 receive 时没有用任何变量来赋值,则该值被抛弃,receive 的这个操作常常被用来做状态同步:

1
<- ch

Close

Channel 还支持第三种操作 close,如果 channel 被 close,表明 channel 不会再 send 任何值了,如果还继续对 channel 执行 receive 操作,当 channel 中的值消耗完毕之后,之后返回的是对应 element type 的 zero value,如果对 channel 执行 send 操作,将会引起 panic:

1
2
close(ch)
ch <- x // panic

Close 操作常常和 for 语句配合使用,表示一个 channel 不再产生新的值:

1
2
3
4

for x := range ch {
fmt.Print(x)
}

Close channel 之后,for 循环将结束。

参考资料

  • The Go Programming Language
三月沙 wechat
扫描关注 wecatch 的公众号