原创作者,公众号【程序员读书】,欢迎关注公众号,转载文章请注明出处哦。

在《Golang学习笔记(十九):Channel初步接触》小节中已经学习了channel的一些基础概念了,总结一下大概是以下几点:
channel是Go语言中gotoutine之间数据通讯的机制。- 可以使用内置函数
make()初始化channel类型。 - 使用
close()函数关闭channel关闭后,不能再往channel发送信息。
好了,简单复习了一下,下面开始深入的学习吧。
channel的分类
同步channel
当我们使用make()函数创建一下channel类型时,如下代码所示:
ch := make(chan int)
此时所创建的channel只能往里面发送一个元素,如果元素没有被另一个gotoutine接收,继续向channel发送元素的gotoutine便会阻塞,这种只能发送单个元素的channel,称为无缓存channel,也称为同步channel,可用于不同goroutine之间的数据同步操作。
package main
import "fmt"
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
// 计数
go counter(ch1)
// 求平方
go squarer(ch1,ch2)
// 在主goroutine中打印同步过来的数据
for x := range ch2 {
fmt.Println(x)
}
}
func counter(ch chan int) {
for x := 0; x < 1000; x++ {
ch <- x
}
close(ch)
}
func squarer(ch1,ch2 chan int){
for x := range ch1 {
ch2 <- x * x
}
close(ch2)
}
在上面的例子中,我们创建了两个goroutine,在counter goroutine产生数值,并同步到另一个squarer goroutine,而squarer goroutine则将元素同步到main goroutine当中,最后再打印输出。
这就是无缓存区的channel的作用,串联不同的goroutine,来达到数据同步的目的。
异步channel
如果想创建一个带缓存区的channel类型,可以使用make()函数的第二个参数来指定channel的队列容量,如:
ch := make(chan int,3)
通过这种创建的channel,也称为异步channel,底层数据结构为一个指定长度元素队列,这里的长度为3,当向channel发送数值时,如果队列未满,则不会发生阻塞,元素会添加在队列的末尾,而接收的goroutine则从队列的头部读取元素。
所以,根据channel是否有缓存区,可将channel分为同步channel和异步channel。
channel的方向性
在上面的例子中,我们看到squarer goroutine对ch1的操作只是读取元素,而对ch2操作只是发送元素,在counter goroutine对ch1的也只是发送元素。
如果从操作的方向性来讲的话,channel可分为只用于发送和只用于接收,也就是单方向channel,定义的方式如下所示:
var ch chan int //可以发送和接收的普通channel
var in <-chan int //只能发送操作的channel
var out chan<- int //只能接收操作的channel
当向用于接收的channel发送元素和从只能用于发送元素的channel接收元素时,都会引发错误。
另外,使用close()函数关闭只能用于接收的channel时,也会引发错误,因为只有发送端才能关闭。
因此,我们可以将上面的例子中两个函数的形参修改为:
func counter(ch chan<- int) {
...//省略函数体
}
func squarer(ch1 <-chan int,ch2 chan<- int){
...//省略函数体
}
你的关注,是我写作路上最大的鼓励!
