💡Today I Learned

Limiting concurrency with errgroup.SetLimit

#Go#Concurrency

I used to reach for a buffered channel as a semaphore whenever I wanted to bound the number of goroutines fanning out from an errgroup.Group. Turns out errgroup has had this built in since Go 1.18.

g, ctx := errgroup.WithContext(ctx)
g.SetLimit(8) // at most 8 active goroutines
for _, job := range jobs {
job := job
g.Go(func() error {
return process(ctx, job)
})
}
if err := g.Wait(); err != nil {
return err
}

SetLimit blocks g.Go until a slot frees up, which keeps memory predictable when the job list is large. Use g.TryGo if you want the non-blocking variant.