You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:25:16