Go语言select关键字运作机制及代码终止原因问询
Go语言select关键字的运作逻辑
select是Go专门用来处理多通道操作的控制结构,核心规则如下:
- 它会同时监听所有case里的通道操作;
- 当至少一个case的通道操作处于就绪状态时,select会随机挑选一个就绪的case执行;
- 如果所有case都未就绪,select会阻塞,直到某个case的操作就绪;
- 若存在default分支,所有case未就绪时会立刻执行default,不会阻塞。
你的代码停止原因详解
先修正并格式化你的代码:
package main import "fmt" func fibonacci(c, quit chan int) { x, y := 0, 1 for { select { case c <- x: fmt.Printf("x = %d, y = %d\n", x, y) x, y = y, x+y case <-quit: fmt.Println("quit") return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() fibonacci(c, quit) }
程序在第10次迭代后停止,核心原因是无缓冲通道的同步特性:
- 你创建的
c是无缓冲通道,无缓冲通道的发送(c <- x)和接收(<-c)必须成对完成——发送方要等接收方准备好接收,操作才算完成,反之亦然。 - 匿名goroutine循环10次接收
c的数据:每接收一次,fibonacci里的c <- x就完成一次,随后更新x、y,进入下一轮select。 - 当匿名goroutine完成10次接收后,会执行
quit <- 0:此时fibonacci的select会检测到<-quit通道有数据可读(处于就绪状态),就会执行这个分支,打印"quit"并返回,直接终止fibonacci函数的无限循环,程序也就停止了。
你误以为c <- x始终可执行,是因为忽略了无缓冲通道的阻塞特性:当匿名goroutine停止接收c的数据后,c <- x会一直阻塞,但此时quit通道的操作已经就绪,select会优先执行就绪的<-quit分支,而不是一直等c <- x。
内容的提问来源于stack exchange,提问作者Lol Lol
相关产品推荐
相关产品推荐

