为何需要Goroutine才能使这段Go代码正常运行?代码异常原因咨询
为什么你的Go代码不加
go send(c)会阻塞? 这个问题的核心是无缓冲通道的同步阻塞特性和Go代码的执行顺序,咱们一步步拆解来看:
不加go send(c)时的死锁原因
你原代码里创建的是无缓冲通道:c := make(chan int),这种通道的关键规则是:
发送操作
c <- val必须等到有接收者准备好接收该值,才能完成;反之,接收操作<-c也必须等到有发送者准备好发送值,才能完成。
当你同步调用send(c)时,执行流程是这样的:
- 主goroutine进入
send函数,启动10个并发的子goroutine,每个子goroutine要往通道c发送10个值。 - 这些子goroutine执行到
c <- j时,发现根本没有任何goroutine在接收通道的数据(因为主goroutine还卡在send函数里,receive(c)一行根本没机会执行),于是全部阻塞在发送操作上。 - 主goroutine卡在
wg.Wait()处,等待这10个子goroutine调用wg.Done(),但子goroutine永远没法完成发送,自然也没法执行wg.Done()——这就形成了死锁:主goroutine等子goroutine,子goroutine等主goroutine提供接收端,互相卡住谁也动不了。
加go send(c)后正常运行的原因
当你把send(c)改成go send(c)时,流程完全变了:
- 主goroutine将
send函数的执行放到一个新的goroutine中,自己立刻继续执行下一行的receive(c)。 receive函数里的for v := range c会持续从通道c接收数据,这就给send里的子goroutine提供了接收端,它们的c <- j操作终于能正常完成。- 当所有子goroutine都完成10次发送后,
send函数里的wg.Wait()结束,随后关闭通道c;receive函数遍历完通道内的所有数据后,因为通道已关闭,循环退出,整个程序正常结束。
总结你的误区
你原本以为send里的wg.Wait()会等内部goroutine完成后再执行receive,但忽略了一个关键前提:send内部的goroutine要完成,必须依赖接收端的存在。同步调用send时,接收端根本没机会启动,导致子goroutine永远阻塞,wg.Wait()永远无法结束,自然到不了receive那一步。
内容的提问来源于stack exchange,提问作者discodowney
相关产品推荐
相关产品推荐

