Go语言中第三个goroutine跟踪另外两个处理goroutine完成状态的最佳实践
Go中实时统计并发goroutine结果的最佳实践
你的核心需求是实时处理并发goroutine的输出结果,同时确保所有结果处理完成后程序才退出,且避免超大缓冲通道和难以扩展的实现方式。最佳实践是结合sync.WaitGroup和通道关闭机制,替代你当前使用的多个done通道方案,代码更简洁且易于扩展。
优化后的实现代码
package main import ( "fmt" "sync" ) func main() { var widgetInventory int = 1000 transactions := make(chan int, 100) var wg sync.WaitGroup fmt.Println("Starting inventory count = ", widgetInventory) // 注册2个处理goroutine到WaitGroup wg.Add(2) go makeSales(transactions, &wg) go newPurchases(transactions, &wg) // 单独goroutine:等待所有生产者完成后关闭通道 go func() { wg.Wait() close(transactions) }() // 实时统计结果:for range会在通道关闭后自动退出循环 for transaction := range transactions { widgetInventory += transaction } fmt.Println("Ending inventory count = ", widgetInventory) } func makeSales(transactions chan int, wg *sync.WaitGroup) { defer wg.Done() // 确保函数退出时标记完成 for i := 0; i < 3000; i++ { transactions <- -100 } } func newPurchases(transactions chan int, wg *sync.WaitGroup) { defer wg.Done() for i := 0; i < 3000; i++ { transactions <- 100 } }
方案优势对比
- 扩展性更强:如果需要新增更多处理goroutine,只需增加
wg.Add(n),并在新goroutine中添加defer wg.Done()即可,无需新增额外的done通道和判断逻辑。 - 代码更简洁:去掉了冗余的
salesDone、purchasesDone通道和复杂的select循环判断逻辑,核心逻辑更清晰。 - 天然保证数据完整性:
for range遍历通道会自动读取所有已发送的数据,直到通道关闭,确保不会遗漏任何结果;而wg.Wait()确保所有生产者都完成发送后才关闭通道,避免提前关闭导致的发送错误。 - 无需超大缓冲通道:缓冲通道只需设置合理的大小(适配生产消费的速度差),不需要覆盖所有结果的数量,避免内存浪费。
内容的提问来源于stack exchange,提问作者Bruce Bradley
相关产品推荐
相关产品推荐

