大量任务并发执行,既要限速也要聚合错误。golang.org/x/sync/errgroup
与带缓冲通道可轻松实现:
package main
import (
"context"
"fmt"
"golang.org/x/sync/errgroup"
)
func main() {
ctx := context.Background()
g, ctx := errgroup.WithContext(ctx)
sem := make(chan struct{}, 8) // 8 个并发
urls := []string{"a","b","c"} // 省略若干
for _, u := range urls {
u := u
g.Go(func() error {
select {
case sem <- struct{}{}:
case <-ctx.Done():
return ctx.Err()
}
defer func(){ <-sem }()
if err := fetch(ctx, u); err != nil {
return fmt.Errorf("fetch %s: %w", u, err)
}
return nil
})
}
if err := g.Wait(); err != nil { /* 统一上报 */ }
}
func fetch(ctx context.Context, url string) error { return nil }
要点:1)使用 ctx
传递取消;2)信号量通道限制并发;3)g.Wait()
返回首个错误并广播取消;4)避免把大任务塞进单个 goroutine,拆分粒度与外部速率/配额对齐。