Golang
的定义了goroutine
间通信的规范,其中对channel
的操作有若干注意项及最佳实践。channel 的源码能自解析以下各项条目。
channel:
- 若使用
channel
之前没有make
,会出现fatal error: all goroutines are asleep - deadlock!
错误。 - 如果没有设置
buffer
,或者buffer
设置为0, 说明channel
没有缓存,只有sender
和receiver
都准备好了后它们的通讯才会发生。如果设置了缓存,只有buffer
满了后send
才会阻塞, 而只有缓存空了后receive
才会阻塞。 make channel
的良好代码规范是要么没有buffer
,要么buffer
设为1
, 参见此。- 往一个已经被
close
的channel
中继续发送数据会导致runtime panic
。 channel
不一定需要被关闭,不再被使用的channel
会被gc
, 参见此。- 重复关闭
channel
会导致runtime panic
。在实际编程中, 不适宜在receiver
端关闭channel
。在有多个sender
的情况下, 也不适合在sender
中关闭channel
。详见此 。 - 已关闭的
channel
也可读, 读出channel
中已有的数据之后再读就是channel
类似的默认值,比如chan int
类型的channel
关闭之后读取到的值为0
。 - 可以关闭一个仍有值被接收的
channel
- 已关闭的
channel
永远不会阻塞 - 只能读的单向
channel
:ch := make(<-chan int, 1)
。只能写的单向channel
:ch := make(chan <- int, 1)
。 channel type. - 多个
goroutine
从/往 一个channel
中receive/send
数据, 不必考虑额外的同步措施。 channel
是先进先出的queue
,接收的数据和发送的数据的顺序一致。
Select :
select
中除default
外,每个case
操作一个channel
。select
中除default
外,各case
执行顺序是随机的。比如同时有多个channel
可以接收数据,那么Go
会伪随机的选择一个case
处理(pseudo-random
)。select
中如果没有default
语句,则会阻塞等待任一case
。select
语句中包含default
和已读取关闭的channel
的case
, 会执行后者。select
可实现超时控制:
select {
case <- ch:
// get data from ch
case <- time.After(2 * time.Second)
// read data from ch timeout
}
select
语句中的case
也可判断channel
是否已关闭:
select {
case e, ok := <-ch1:
...
case e, ok := <-ch2:
...
default:
}
- 要使用
select
持续读取channel
, 一般在select
加for
循环且提供退出机制, 如
for{
select {
case ...
case <-ctx.done():
return
}
}
- 关于
for{}
和select{}
的开销见此.
Range:
range
会轮询channel
直到channel
关闭, 若channel
不关闭会阻塞。- 可以防止读取已经关闭的
channel
造成读到数据为通道所存储的数据类型的零值。
Reference:
- https://colobu.com/2016/04/14/Golang-Channels/
- http://www.legendtkl.com/2017/07/30/understanding-golang-channel/