Go语言通道赋值机制解析:两段代码输出差异原因咨询
Goroutine与通道赋值的行为差异分析
情况1:移除b = a时,输出为2
对应代码:
package main import "fmt" func main() { ch := make(chan int) a := ch b := ch a = make(chan int) go f(a, b) a = make(chan int) go f(a, b) a = make(chan int) go f(a, b) go func() { a <- 1 }() fmt.Println(<-ch) } func f(a, b chan int) { b <- 1 + <-a }
运行逻辑拆解:
- 初始状态:
a和b都指向同一个通道ch。 - 每次执行
a = make(chan int)时,a会指向一个新创建的通道,但b始终保持指向最初的ch。 - 三次启动的
fgoroutine中,b参数都是ch,而a参数分别是三个不同的新通道。 - 最后启动的匿名goroutine,只会往第三个新通道里发送1。
- 只有第三个
f能收到这个1,计算1+1=2后往ch发送;另外两个f的a通道永远收不到值,会一直阻塞,但主程序不会等待它们,最终从ch读到的就是2。
情况2:添加b = a时,输出为4
对应代码:
package main import "fmt" func main() { ch := make(chan int) a := ch b := ch a = make(chan int) go f(a, b) b = a a = make(chan int) go f(a, b) b = a a = make(chan int) go f(a, b) b = a go func() { a <- 1 }() fmt.Println(<-ch) } func f(a, b chan int) { b <- 1 + <-a }
运行逻辑拆解:
b = a的作用是更新b的指向,让它和当前的a指向同一个新通道,从而形成了一条通道链:- 第一次操作:
a指向新通道1,启动f(新通道1, ch);然后b改为指向新通道1。 - 第二次操作:
a指向新通道2,启动f(新通道2, 新通道1);然后b改为指向新通道2。 - 第三次操作:
a指向新通道3,启动f(新通道3, 新通道2);然后b改为指向新通道3。
- 第一次操作:
- 最后匿名goroutine往新通道3发送1,触发链式计算:
- 第三个
f收到1,计算1+1=2,往新通道2发送。 - 第二个
f收到2,计算2+1=3,往新通道1发送。 - 第一个
f收到3,计算3+1=4,往ch发送。
- 第三个
- 主程序从
ch读到的就是最终累加后的4。
总结b = a的具体行为
b = a是通道变量的赋值操作:在Go中,通道是引用类型,赋值只会复制通道的引用(即指向通道的指针),不会复制通道本身。每次执行b = a后,b就会和a指向同一个通道实例,这就把后续f的b参数和前一个f的a参数关联起来,形成了传递数据的链条,最终让初始的1经过三次1+的累加,传到了ch中。
内容的提问来源于stack exchange,提问作者Kirti Dhiman
相关产品推荐
相关产品推荐

