如何让Go Channel工作池的结果数量与任务数量不同?
解决工作池结果数量与任务数量不一致的阻塞问题
你的问题核心是主 goroutine 固定等待与任务数相等的结果,但部分任务未向结果通道发送数据,导致永久阻塞。这里提供两种可行的解决思路:
方法一:用 WaitGroup 跟踪任务完成,关闭结果通道后读取所有结果
通过 sync.WaitGroup 监控所有任务的完成状态,待所有 worker 处理完任务后关闭结果通道,主 goroutine 用 range 遍历通道读取所有已发送的结果,不会阻塞。
修改后的代码如下:
import ( "fmt" "math/rand" "sync" "time" ) type DemoResult struct { Name string Rate int } func random(min, max int) int { return rand.Intn(max-min) + min } func worker(id int, jobs <-chan int, results chan<- DemoResult, wg *sync.WaitGroup) { defer wg.Done() // 任务完成时标记WaitGroup计数减一 for j := range jobs { fmt.Println("worker", id, "started job", j) time.Sleep(time.Second) fmt.Println("worker", id, "finished job", j) myrand := random(1, 4) if myrand == 2 { results <- DemoResult{Name: "succ", Rate: j} } // 失败时不发送结果 } } func main() { rand.Seed(time.Now().UTC().UnixNano()) // 只初始化一次随机数种子 const numJobs = 5 jobs := make(chan int, numJobs) results := make(chan DemoResult) var wg sync.WaitGroup // 启动worker,每个worker对应一个WaitGroup计数 for w := 1; w <= 3; w++ { wg.Add(1) go worker(w, jobs, results, &wg) } // 发送任务 for j := 1; j <= numJobs; j++ { jobs <- j } close(jobs) // 关闭任务通道,worker会在读完所有任务后退出循环 // 启动goroutine,等所有worker完成后关闭结果通道 go func() { wg.Wait() close(results) }() // 遍历结果通道,读取所有已发送的结果,直到通道关闭 for out := range results { if out.Name == "succ" { fmt.Printf("%v\n", out) } } }
方法二:统一发送结果(成功/失败都发)
如果你可以接受每个任务都发送结果,哪怕是失败状态,只需要把注释的 else 分支打开,这样结果通道的元素数量就和任务数一致,主循环的固定次数读取就不会阻塞。这种方式更简单,但需要所有任务都产生结果。
另外注意:你原来的 random 函数每次调用都重新设置随机数种子,会导致生成的随机数重复,建议在 main 函数开头只初始化一次种子,就像上面代码里那样。
内容的提问来源于stack exchange,提问作者pvd
相关产品推荐
相关产品推荐

