Go 并发编排:用 errgroup 协同多 goroutine 与统一错误取消

test12026-09-120 次阅读

传统 WaitGroup 的局限

sync.WaitGroup 能等一组 goroutine 跑完,但它不处理错误,也无法在某个任务失败时通知其他任务取消。真实业务里往往要求"任意一个失败就整体失败",errgroup 正好补上这块。

errgroup 基础用法

package main

import (
	"context"
	"fmt"
	"time"

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

func fetch(ctx context.Context, url string) (string, error) {
	select {
	case <-time.After(50 * time.Millisecond):
		return url, nil
	case <-ctx.Done():
		return "", ctx.Err()
	}
}

func main() {
	g, ctx := errgroup.WithContext(context.Background())

	urls := []string{"a", "b", "c"}
	res := make([]string, len(urls))

	for i, u := range urls {
		i, u := i, u
		g.Go(func() error {
			s, err := fetch(ctx, u)
			if err != nil {
				return err
			}
			res[i] = s
			return nil
		})
	}

	if err := g.Wait(); err != nil {
		fmt.Println("部分任务失败:", err)
		return
	}
	fmt.Println(res)
}

关键点解释

  • errgroup.WithContext 返回一个带取消能力的 ctx,任意一个 g.Go 返回非 nil 错误,ctx 就会被取消。
  • 循环里 i, u := i, u 是必要的,否则闭包捕获的是同一个循环变量。
  • g.Wait 返回第一个非 nil 错误,其余 goroutine 因 ctx 取消而提前退出。

限制并发数

任务很多时,用带信号量的 errgroup 控制并发上限,避免瞬间打满下游:

func run(tasks []string, limit int) error {
	g, ctx := errgroup.WithContext(context.Background())
	ch := make(chan struct{}, limit)

	for _, t := range tasks {
		t := t
		ch <- struct{}{}
		g.Go(func() error {
			defer func() { <-ch }()
			return doWork(ctx, t)
		})
	}
	return g.Wait()
}
T

test1

文章作者

传统 WaitGroup 的局限 sync.WaitGroup 能等一组 goroutine 跑完,但它不处理错误,也...

分类
技术
发布时间
2026-09-12
字数
约 1308 字
阅读
0 次