Go语言不使用wg.Wait()实现并发goroutine提前退出与完成检测
优化实现方案
你现有代码的核心逻辑是正确的,但存在一个明显缺陷:带default分支的select会让循环陷入无意义的忙等,持续占用CPU资源,以下是更符合Go语言惯用法的优雅实现:
核心优化点
- 移除忙等逻辑:去掉
select的default分支,让select阻塞等待事件触发,避免空转消耗资源 - 简化计数逻辑:每次收到成功返回的false结果就累加计数,累计到3时直接返回即可,不需要额外的轮询判断
- 无goroutine泄露风险:现有代码中channel已经设置了3个缓冲,即使提前返回,剩余goroutine写channel也不会阻塞,不会发生泄露;如果子函数支持中断,还可以额外传入
context.Context在提前返回时终止剩余goroutine的执行,避免无用计算
优化后代码示例
package main import ( "errors" "fmt" "time" ) type checkResult struct { isPrimary bool err error } func main() { x := "something" res, err := IsAPrimaryColour(x) if err != nil { fmt.Printf("Error: %v\n", err) return } fmt.Printf("Result: %v\n", res) } func IsAPrimaryColour(value interface{}) (bool, error) { resChan := make(chan checkResult, 3) start := time.Now() // 合并重复的启动逻辑,不需要重复写三次匿名函数 checkFuncs := []func(interface{}) (bool, error){IsRed, IsGreen, IsBlue} for _, f := range checkFuncs { go func(check func(interface{}) (bool, error)) { isOk, err := check(value) resChan <- checkResult{isPrimary: isOk, err: err} fmt.Printf("%T done in %v\n", check, time.Since(start)) }(f) } received := 0 for received < 3 { select { case res := <-resChan: received++ if res.err != nil { fmt.Println("收到错误,直接返回") return false, res.err } if res.isPrimary { fmt.Println("收到true结果,直接返回") return true, nil } } } // 三个校验函数都返回false fmt.Println("所有校验都返回false") return false, nil } func IsRed(value interface{}) (bool, error) { return false, nil } func IsGreen(value interface{}) (bool, error) { time.Sleep(time.Millisecond * 100) return true, nil } func IsBlue(value interface{}) (bool, error) { time.Sleep(time.Millisecond * 200) return false, errors.New("something went wrong") }
内容的提问来源于stack exchange,提问作者user15558657
相关产品推荐
相关产品推荐

