如何判断协程任务执行是否成功

举报
码乐 发表于 2026/01/21 09:30:33 2026/01/21
【摘要】 1 背景简介工作业务时常有并发任务执行并且需要检查执行结果。协程(goroutine)执行完任务后判断其业务是否“正确”,本质上涉及 结果传递、错误传播、并发控制、可观测性 四个方面。本文按常见 → 进阶 → 工程化系统说明可用的技术方法,并给出示例。 2 最常用方法channel通过 channel 返回结果 + 错误(推荐)核心思想:协程goroutine 不“自己判断成功与否”,而是...

1 背景简介

工作业务时常有并发任务执行并且需要检查执行结果。协程(goroutine)执行完任务后判断其业务是否“正确”,本质上涉及 结果传递、错误传播、并发控制、可观测性 四个方面。

本文按常见 → 进阶 → 工程化系统说明可用的技术方法,并给出示例。

2 最常用方法channel

  • 通过 channel 返回结果 + 错误(推荐)

核心思想:

协程goroutine 不“自己判断成功与否”,而是 返回结果和 error,由调用方判断

    type Result struct {
        Value int
        Err   error
    }

    func worker(ch chan<- Result) {
        // 业务逻辑
        if false { // 业务失败
            ch <- Result{Err: errors.New("业务错误")}
            return
        }
        ch <- Result{Value: 100}
    }

    func main() {
        ch := make(chan Result)

        go worker(ch)

        res := <-ch
        if res.Err != nil {
            fmt.Println("失败:", res.Err)
            return
        }
        fmt.Println("成功:", res.Value)
    }

适合:

单个 / 少量 goroutine

有明确返回值的业务

  • 2 使用 sync.WaitGroup + 共享错误收集

核心思想:

等待所有 goroutine 完成

通过 channel 或 atomic / mutex 收集错误

    var wg sync.WaitGroup
    errCh := make(chan error, 10)

    for i := 0; i < 5; i++ {
        wg.Add(1)
        go func(i int) {
            defer wg.Done()
            if i == 3 {
                errCh <- fmt.Errorf("任务 %d 失败", i)
            }
        }(i)
    }

    wg.Wait()
    close(errCh)

    for err := range errCh {
        if err != nil {
            fmt.Println("发现错误:", err)
        }
    }

适合:

批量并发任务

需要收集多个任务执行状态

2 上下文进阶:工程中最常用的判断方式

  • 通过 context.Context 控制 & 判断执行结果

核心思想:

			goroutine 接收 context

出错 / 超时 / 取消都会反映到 ctx.Err()

    func worker(ctx context.Context) error {
        select {
        case <-time.After(1 * time.Second):
            return nil
        case <-ctx.Done():
            return ctx.Err()
        }
    }

    func main() {
        ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
        defer cancel()

        err := worker(ctx)
        if err != nil {
            fmt.Println("失败:", err)
        }
    }

** 适合:

超时控制

请求级任务

微服务 / RPC / HTTP

  • 使用 errgroup(强烈推荐)

errgroup 是 Go 官方扩展库,专门解决:并发执行 + 错误判断

    import "golang.org/x/sync/errgroup"

    func main() {
        var g errgroup.Group

        for i := 0; i < 5; i++ {
            i := i
            g.Go(func() error {
                if i == 2 {
                    return fmt.Errorf("任务 %d 出错", i)
                }
                return nil
            })
        }

        if err := g.Wait(); err != nil {
            fmt.Println("至少一个任务失败:", err)
        }
    }

** 优点:

自动收集第一个错误

代码简洁

工程实践首选

4 如何“判断业务正确性” 不仅仅是 error

  • 明确「业务成功」的判定标准

推荐使用 显式状态结构体:

    type TaskResult struct {
        Success bool
        Code    int
        Msg     string
    }

    func worker() TaskResult {
        if xxx {
            return TaskResult{Success: false, Code: 400, Msg: "校验失败"}
        }
        return TaskResult{Success: true}
    }

而不是:

不推荐

			func worker() bool
  • 使用断言 / 校验逻辑(业务层)

    func validate(result Result) error {
        if result.Value <= 0 {
            return errors.New("结果不合法")
        }
        return nil
    }
    

在 goroutine 外统一校验。

5 工程化手段(生产环境必备)

  • 日志 + Trace ID(定位正确性)

    log.WithFields(log.Fields{
        "task_id": id,
        "result":  result,
    }).Info("task finished")
    

判断是否正确 ≠ 只靠返回值
还需要 日志 + 上下文

  • 指标 & 监控(最终判断)

成功率

失败次数

超时数量

    task_success_total
    task_failure_total

    Prometheus / OpenTelemetry

** 常见错误做法(避免)

goroutine 里 panic 当失败
goroutine 里打印日志就当处理完成
不返回结果,只靠全局变量
不等待 goroutine 就判断成功

6 小结

选型建议

单任务推荐方式 channel + error
多任务推荐方式 WaitGroup + error channel
复杂并发推荐方式 errgroup
超时取消推荐方式 context
工程化推荐方式 errgroup + context + 日志 + 监控。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。