Thinking_Out_Loud

《Go程序设计语言》读书笔记#7

2018-10-10

第八章 goroutine和通道

< P225 >

  • 同类型的chan可以用==比较,当两者指向同一channel data structure时结果为真;
  • 容量大于零都算buffered channelcap为零即没有缓冲,发送方要一直等到接收方接收;

< P229 >

  • channel被关闭后,后续的发送会引发panic,而后续的接收只会得到零值;可以增加第二个接受布尔类型的返回值检测是否关闭,更简便的方法是用rangechannel关闭后range循环也结束;
  • 关闭一个已关闭的channel或值为nil的都会引发panic
  • 当GC检测到channelunreachable时,不管关闭与否都会将其GC,所以关闭channel不是必要的;

< P230 >

  • 加上助记符<-变成unidirectional channel,如<-chan Tchan<- T,表示数据只能单方向传输,会在编译时检查是否有违法的操作;
  • read-onlychannel使用close方法会引发编译错误;
  • 存在从双向channel到单向的隐式转换,但这种转换是不可逆的;

< P232 >

  • lencap方法查看channel的当前缓存元素个数和容量;
  • 不要把channel当作队列使用,因为channel和当前goroutine的时序联系很深,可能会阻塞运行;
  • goroutine leak发生在goroutine向一个channel发送数据时被阻塞,而该channel之后也不会被取出数据,所以阻塞一直持续;

< P236 >

使用匿名函数的goroutine也要注意变量的捕获,应该用传参或者新的局部变量捕获

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func main() {

var ch = make(chan struct{})
for _, s := range "abcdefg" {
//s := s // 用新的局部变量
go func(s rune) {
fmt.Printf("%c\n", s)
ch <- struct{}{}
}(s) // 或者传参
}

for range "abcdefg" {
<-ch
}
}

< P245 >

  • 没有caseselect结构会wait forever
  • 当多个caseready时,select随机选择一个运行;
  • 使用time.Tick函数会新建一个goroutine,只建议全局都用到的时候才使用,不然会造成goroutine leak;一般推荐使用time.NewTicker,使用返回对象的Stop方法终止计时goroutine
  • select里的case只能存在channel的接收或发送操作;
  • 对值为nilchannel的接收或发送都永远阻塞;配合select可以作为选项开关;
  • select加入default可以用作对channel的查询(polling channel);否则会停留直到其中一个case可行;

< P252 >

poll一个closed channel可以取得零值(以及false)。