Go语言并发代码打印结果为串行不符合预期,求问题原因与解决方案
问题原因
你的代码中两个goroutine没有任何同步协调逻辑,Go运行时对goroutine的调度没有顺序保证,无同步约束时单个goroutine会连续执行完所有逻辑,才会切换到其他goroutine,所以会出现一侧输出全部打印完成后才打印另一侧的情况,和预期交替效果不符。
修复方案
要实现严格的交替打印,需要通过channel来控制两个goroutine的执行时序,每次打印完成后通知对方执行,自身阻塞等待下一轮执行信号。修复后可实现预期效果的代码如下:
package main import ( "fmt" "sync" ) func main() { var wg sync.WaitGroup wg.Add(2) // 两个无缓冲channel作为执行信号量 hiSig := make(chan struct{}) gSig := make(chan struct{}) // 打印偶数的goroutine go func() { defer wg.Done() for i := 0; i < 4; i += 2 { <-hiSig // 等待执行信号 fmt.Println("hi", i) gSig <- struct{}{} // 通知打印奇数的goroutine执行 } }() // 打印奇数的goroutine go func() { defer wg.Done() for i := 1; i < 4; i += 2 { <-gSig // 等待执行信号 fmt.Println("g", i) if i != 3 { // 最后一轮执行不需要回发信号,避免channel泄漏 hiSig <- struct{}{} } } }() hiSig <- struct{}{} // 触发第一次hi打印,启动交替流程 wg.Wait() // 关闭channel close(hiSig) close(gSig) }
逻辑说明
hiSig和gSig是两个无缓冲channel,用来做两个goroutine的执行时序同步,无缓冲channel的收发操作都是阻塞的,只有收发双方都就绪时操作才会完成,刚好可以用来做执行权限的交接- 主协程先往
hiSig发送信号,让打印hi的goroutine先执行,打印完成后往gSig发信号,通知打印g的goroutine执行,自己进入阻塞等待下一轮信号 - 打印g的goroutine收到信号后执行打印,非最后一轮的话回发信号给hi的goroutine,循环往复直到所有内容打印完成
- WaitGroup用来等待两个goroutine全部执行完成后再退出主协程
内容的提问来源于stack exchange,提问作者sai
相关产品推荐
相关产品推荐

