Extensiones de errgroup y golang.org/x/sync
Goroutines coordinadas con cancelación por primer error.
Busca en todas las páginas de la documentación
Goroutines coordinadas con cancelación por primer error.
golang.org/x/sync/errgroup agrupa goroutines que comparten un destino: un fallo cancela el resto y presenta un único error desde Wait.
Paquetes relacionados en x/sync añaden paralelismo limitado (SetLimit), deduplicación (singleflight) y semáforos contadores (semaphore).
Estas extensiones llenan vacíos en el paquete sync de la biblioteca estándar para la orquestación de servicios.
Tarjeta de receta de referencia rápida - lista para copiar y pegar.
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(4)
g.Go(func() error { return stepA(ctx) })
g.Go(func() error { return stepB(ctx) })
if err := g.Wait(); err != nil {
return err
}Cuándo usar esto:
SetLimit).singleflight.Group.semaphore.Weighted.// go.mod: module example.com/errgroupdemo
package main
import (
"context"
"fmt"
"sync"
"time"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
"golang.org/x/sync/singleflight"
)
func fetch(ctx context.Context, name string, delay time.Duration, fail bool) error {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(delay):
if fail {
return fmt.Errorf("%s failed", name)
}
fmt.Println("fetched", name)
return nil
}
}
func parallelFetch(ctx context.Context) error {
g, ctx := errgroup.WithContext(ctx)
g.SetLimit(2)
tasks := []struct {
name string
d time.Duration
fail bool
}{
{"users", 20 * time.Millisecond, false},
{"orders", 30 * time.Millisecond, false},
{"inventory", 10 * time.Millisecond, true},
}
for _, t := range tasks {
t := t
g.Go(func() error {
return fetch(ctx, t.name, t.d, t.fail)
})
}
return g.Wait()
}
func dedupeLoad(g *singleflight.Group, key string) (string, error) {
v, err, _ := g.Do(key, func() (any, error) {
time.Sleep(50 * time.Millisecond)
return "data-for-" + key, nil
})
if err != nil {
return "", err
}
return v.(string), nil
}
func main() {
ctx := context.Background()
if err := parallelFetch(ctx); err != nil {
fmt.Println("parallel:", err)
}
var sf singleflight.Group
var wg sync.WaitGroup
for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
defer wg.Done()
s, _ := dedupeLoad(&sf, "account:42")
fmt.Println(s)
}()
}
wg.Wait()
sem := semaphore.NewWeighted(1)
if err := sem.Acquire(ctx, 1); err == nil {
defer sem.Release(1)
fmt.Println("critical section")
}
}Lo que esto demuestra:
WithContext vincula la vida útil de las goroutines a la cancelación compartida.SetLimit(2) evita que se realicen más de dos fetchings a la vez.singleflight ejecuta un cargador por clave mientras los que esperan comparten el resultado.semaphore.Weighted bloquea de forma consciente del contexto, a diferencia de los trucos de canales puros.errgroup.Group incrusta un WaitGroup más una ranura de error protegida por un mutex.Go activa cancel en el contexto derivado de WithContext.SetLimit(n) utiliza un semáforo de canal interno; n < 1 significa ilimitado.singleflight.Do agrupa llamadas concurrentes con la misma clave hasta que la función líder retorna.| Paquete | Tipo | Rol |
|---|---|---|
| errgroup | Group | Tareas paralelas, gana el primer error |
| semaphore | Weighted | Adquirir/liberar capacidad con ctx |
| singleflight | Group | Suprimir trabajo duplicado en curso |
| syncmap | Map | Mapa concurrente (nicho; a menudo preferir mapa plano + mutex) |
// errgroup sin cancel - usar cuando los fallos no deben detener a los hermanos
var g errgroup.Group
g.Go(func() error { return maybeFail() })
_ = g.Wait()errgroup.Group simple cuando el éxito parcial es aceptable y fusionas los errores tú mismo.ctx derivado de WithContext a las I/O, no al padre.ctx padre dentro de Go después de que un hermano haya fallado - El trabajo continúa después de la cancelación. Solución: Usa solo el ctx derivado.Go después de Wait - Comportamiento indefinido; crea un nuevo Grupo por lote. Solución: Un grupo por operación lógica.ctx en tareas largas - Las ranuras permanecen ocupadas hasta que la tarea finaliza. Solución: Honra ctx.Done() en los cuerpos de fetch.Go - Causa el cierre del proceso; errgroup no recupera. Solución: Evita los panics; usa envoltorios seguros en producción.sync.WaitGroup para uniones simples.| Alternativa | Usar Cuando | No Usar Cuando |
|---|---|---|
sync.WaitGroup + canal de error | Lógica de fusión de errores personalizada | El primer error-cancelación estándar es suficiente |
parallel.For (iterador Go 1.22+) | Rebanadas de CPU con errores síncronos | I/O mixta con cancelación |
| Canal de pool de workers | Cola de larga duración | Lote paralelo de un solo uso |
context.WithCancel manual | Cancelación parcial de grano fino | Código repetitivo sin beneficio |
Retorno de error automático y cancelación de contexto opcional ante el primer fallo.
Cuando cualquier fallo deba detener las goroutines hermanas; típico para manejadores de solicitudes que se ramifican.
Paralelismo ilimitado; lo mismo que no llamar a SetLimit.
Usa una rebanada con mutex, o ejecuta tareas secuencialmente, o tipos de multi-error de terceros.
errgroup intencionalmente devuelve uno.
No; solo deduplica cargas concurrentes.
Emparejar con una caché real para resultados almacenados.
Solo dentro de un proceso.
Usa bloqueos distribuidos o caché para deduplicación entre instancias.
Inicia una tarea lenta y una tarea rápida que falle; afirma que la lenta retorna context.Canceled.
Semaphore soporta adquisición ponderada, cancelación de contexto y una API más clara para límites dinámicos.
A menudo sí para ayudantes de envío/recepción concurrentes vinculados al ciclo de vida del stream.
Es un módulo de extensión oficial de Go versionado por separado de la biblioteca estándar.
Fíjalo en go.mod y verifícalo en tiempo de CI.
Deriva WithContext del hijo del ctx padre para que la cancelación externa siga aplicándose.
Las goroutines aún se ejecutan pero es posible que haya fugas si se bloquean para siempre; siempre llama a Wait.
Versiones de Stack: Esta página fue escrita para Go 1.26.x (predeterminado Green Tea GC, go fix modernizers - verificar parche en la compilación), chi (última - verificar en la compilación), gin (última - verificar en la compilación), echo (última - verificar en la compilación), google.golang.org/grpc (última - verificar en la compilación), sigs.k8s.io/controller-runtime (última - verificar en la compilación), kubebuilder (última - verificar en la compilación), tinygo (última - verificar objetivos de placa en la compilación), wazero (última - verificar en la compilación) y golangci-lint (última - verificar conjunto de linters en la compilación).
Revisado por Chris St. John·Última actualización: 16 jul 2026