Go语言无缓冲通道竞态问题:为何输出不稳定?
问题分析与解决方案
1. 为何INSERT;输出会丢失
无缓冲通道的发送操作确实会阻塞到接收方接收,但如果发送完成后主goroutine直接退出,负责接收并打印的goroutine可能还没完成打印操作就被程序强制终止了。Go程序退出时会直接终止所有未执行完成的goroutine,导致本该打印的内容没来得及输出,看起来像是“丢失”了。
2. SplitChan函数为何能返回
SplitChan应该是在内部启动了一个goroutine来执行包含cmd := <-c的Split逻辑——goroutine是异步执行的,启动它的函数不会等待goroutine完成才返回。只要SplitChan自身的代码执行完毕(比如启动goroutine的语句执行完),就会直接返回,和内部goroutine是否阻塞无关。
如何保证输出一致
核心是要同步goroutine的生命周期,确保所有负责处理数据的goroutine完成任务后,程序才退出:
- 使用
sync.WaitGroup:启动接收goroutine前调用wg.Add(1),接收goroutine处理完所有数据后调用wg.Done(),主goroutine最后调用wg.Wait()等待任务结束。 - 关闭通道:在发送完所有数据后关闭通道,让接收方的循环能正常退出,避免goroutine泄漏。
示例修正代码:
package main import ( "fmt" "sync" ) func Split(c chan string, wg *sync.WaitGroup) { defer wg.Done() // 遍历通道直到通道被关闭 for cmd := range c { fmt.Println(cmd) } } func main() { c := make(chan string) var wg sync.WaitGroup wg.Add(1) go Split(c, &wg) c <- "INSERT;" close(c) // 关闭通道,告知接收方没有更多数据 wg.Wait() // 等待接收goroutine处理完所有数据再退出 }
内容的提问来源于stack exchange,提问作者GProssliner
相关产品推荐
相关产品推荐

