Go 语言入门 14—Channel
Channel
channel(通道)在 go 语言中通常用于 goroutine 之间通信,可以连接不同的 goroutine , channel 是一种可以让一个 goroutine 发送特定值到另一个 goroutine 的通信机制。
channel 是一种特殊的类型,类似于数据结构中的队列,其中的元素遵循先入先出的规则,同时每一个通道都需要指定对应的类型,指定类型之后该通道就只能发送或接受对应类型的数据。
通道声明
通道初始化
通道是引用类型,其默认值为 nil ,如果一个通道只声明没有初始化那么直接使用这个通道会触发 panic 。通道初始化可以使用 make 函数进行。
语法:
使用 make 函数初始化通道时,需要指定通道的元素类型,通道的缓冲大小可以省略。
代码示例:
通道操作
在 go 语言中,通道一共有 3 种操作,分别是:发送、接收和关闭,其中发送和接收都需要使用到一个符号:<-
,关闭使用 close
函数。
初始化一个通道:
发送:将一个 int 类型发送到通道里面
接收:从通道里面接收一个 int 类型的元素
关闭:关闭一个通道
代码示例:
上述代码中启动了两个 goroutine ,一个将元素发送到通道中,另一个从通道中取出元素。
运行结果:
无缓冲通道
在使用 make 函数初始化通道时,如果没有指定缓冲区的大小,那么就默认是无缓冲通道,例如上面的代码示例中使用的就是无缓冲通道,无缓冲通道在发送值的时候必须要有一个对应的 goroutine 接收值才行,否则就会报错。
代码示例:
上述代码中,使用的就是无缓冲通道,所以在第 3 行发送一个值到通道中时就会报错,导致程序运行失败。
运行结果:
有缓冲通道
有缓冲通道表示通道里面可以缓冲一部分数据,发送的数据可以暂时的保存在通道的缓冲区,不需要有 goroutine 立即去接收。要使用有缓冲通道只需要在使用 make 函数初始化通道时指定缓冲区的大小即可,只要指定的缓冲区的大小大于 0 就行,缓冲区大小表示通道内能够暂存的元素个数。
针对上面无缓冲的代码,只需要在初始化时指定缓冲区大小,使其变成有缓冲通道,就不会报错了。
代码示例:
运行结果:
close
可以使用 close 关闭通道,当一个通道不再往里面发送值或者接收值的时候,就需要将通道关闭,通道是可以被垃圾回收机制回收的,它和关闭文件不一样,在结束操作之后关闭文件是必须的,但关闭通道不是必须的。
代码示例:
代码中 send 方法循环发送从 0 到 9 到通道中,当发送完成之后就关闭通道,然后 receive 循环循环接收通道中的值,当通道被关闭之后接收到的 ok 值为 false ,则跳出循环。
关闭通道注意事项:
往一个已关闭的通道发送值会发生 panic。
从一个已关闭的通道接收值会一直接收到通道为空,通道为空之后再接收返回通道元素类型的默认值。
对一个已关闭的通道再次关闭会发生 panic
循环接收
在上面的代码中,receive 函数通过接收值的时候接收 ok 返回值判断通道是否关闭,除了使用这种方法之外,还可以使用for range
循环接收的方式判断发送方是否已经关闭通道,如果发送方关闭通道了,那么循环就会自动退出。
代码示例:
上述代码 receive 函数中通过 for range 的方式从通道中获取值,当发送方关闭了通道之后,for range 循环也就自动退出了。
单向通道
之前介绍的一直都是一个通道既可以发送值也可以接收值,在并发编程中,通道经常被作为参数传递给不同的函数,有时候需要在不同的函数中对通道进行限制,这就需要用到单向通道了。
chan <- 类型
:只能发送值到通道中,不能从通道中接收值<- chan 类型
:只能从通道中接收值,不能发送值到通道中
对上面代码进行修改:
在代码中,send 函数的参数为只能发送类型,receive 函数的参数为只能接收类型,所以在 send 函数体内部就不能从通道接收,在 receive 函数体内部就不能发送值到通道中。例如在 receive 内往通道发送一个值就会报错:send to the receive-only type <-chan int
。
运行结果:
版权声明: 本文为 InfoQ 作者【良猿】的原创文章。
原文链接:【http://xie.infoq.cn/article/2ce11f72f86571fd3ebfcc267】。文章转载请联系作者。
评论