Noções Básicas de Concorrência Avançada
10 exemplos para você começar com Concorrência Avançada - 7 básicos e 3 intermediários.
Busque em todas as páginas da documentação
10 exemplos para você começar com Concorrência Avançada - 7 básicos e 3 intermediários.
go mod init example.com/advconc.go get golang.org/x/sync/errgroup golang.org/x/time/rate.go run . a partir do diretório de pacote de cada trecho.Inicie N workers que leem jobs até que o canal seja fechado.
package main
import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for j := range jobs {
fmt.Printf("worker %d job %d\n", id, j)
}
}
func main() {
const workers = 3
jobs := make(chan int, 10)
var wg sync.WaitGroup
for i := 0; i < workers; i++ {
wg.Add(1)
go worker(i, jobs, &wg)
}
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
wg.Wait()
}close(jobs) sinaliza aos workers para saírem após esvaziar.WaitGroup espera pelos workers antes que main retorne.Relacionado: Pools de Workers e Filas de Tarefas - dimensionamento e padrões de desligamento
Limite goroutines em execução sem um conjunto de workers dedicado.
package main
import (
"fmt"
"sync"
)
func main() {
sem := make(chan struct{}, 2) // max 2 concorrentes
var wg sync.WaitGroup
for i := 0; i < 6; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
sem <- struct{}{}
defer func() { <-sem }()
fmt.Println("task", n)
}(i)
}
wg.Wait()
}golang.org/x/sync/semaphore quando precisar de Acquire(ctx) com cancelamento.Relacionado: Limitação de Taxa e Backpressure - baldes de tokens e descarte
Execute goroutines relacionadas; o primeiro erro cancela as demais.
package main
import (
"context"
"fmt"
"time"
"golang.org/x/sync/errgroup"
)
func main() {
g, ctx := errgroup.WithContext(context.Background())
g.Go(func() error {
return fmt.Errorf("task a failed")
})
g.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
case <-time.After(time.Second):
return nil
}
})
if err := g.Wait(); err != nil {
fmt.Println("errgroup:", err)
}
}WithContext cancela ctx quando qualquer Go retorna um erro não nulo.ctx em funções Go de longa execução.Wait bloqueia até que todas as goroutines terminem e retorna o primeiro erro.Relacionado: errgroup e Extensões golang.org/x/sync - SetLimit e padrões
Uma goroutine produz, outra consome através de um canal.
package main
import (
"fmt"
)
func main() {
out := make(chan int)
go func() {
defer close(out)
for i := 1; i <= 3; i++ {
out <- i * 10
}
}()
for v := range out {
fmt.Println(v)
}
}range sobre o canal recebe até o fechamento.Relacionado: Fan-In, Fan-Out e Estágios de Pipeline - grafos multiestágios
Distribua itens para workers, espere a conclusão.
package main
import (
"fmt"
"sync"
)
func main() {
items := []int{1, 2, 3, 4}
var wg sync.WaitGroup
for _, item := range items {
wg.Add(1)
go func(v int) {
defer wg.Done()
fmt.Println("process", v)
}(item)
}
wg.Wait()
}Relacionado: Concorrência em Produção: Padrões Além do Hello Goroutine - quando limitar o fan-out
Pare os workers quando o contexto for concluído.
package main
import (
"context"
"fmt"
"time"
)
func worker(ctx context.Context, id int) {
for {
select {
case <-ctx.Done():
fmt.Println("worker", id, "stop")
return
default:
fmt.Println("worker", id, "tick")
time.Sleep(200 * time.Millisecond)
}
}
}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel()
go worker(ctx, 1)
<-ctx.Done()
time.Sleep(100 * time.Millisecond)
}select em ctx.Done() é obrigatório em loops de produção.WithTimeout deriva um prazo do contexto pai.WaitGroup quando múltiplos workers precisarem sair antes de prosseguir.Relacionado: Noções Básicas de Contexto - WithCancel e prazos
Contador sem bloqueio para métricas e IDs.
package main
import (
"fmt"
"sync"
"sync/atomic"
)
func main() {
var n atomic.Int64
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
n.Add(1)
}()
}
wg.Wait()
fmt.Println("count", n.Load())
}atomic.Int64 é tipado e mais claro do que int64 bruto com AddInt64.go test -race se você misturar atômicos com leituras não atômicas.Relacionado: Operações sync/atomic - CAS e quando os atômicos vencem
Parada graciosa: cancela o contexto, fecha os jobs, espera pelos workers.
package main
import (
"context"
"fmt"
"sync"
"time"
)
func pool(ctx context.Context, jobs <-chan int, n int) *sync.WaitGroup {
var wg sync.WaitGroup
for i := 0; i < n; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case j, ok := <-jobs:
if !ok {
return
}
fmt.Println(id, "handled", j)
}
}
}(i)
}
return &wg
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
jobs := make(chan int, 4)
wg := pool(ctx, jobs, 2)
for j := 1; j <= 4; j++ {
jobs <- j
}
close(jobs)
cancel()
wg.Wait()
}ctx.Done() combinado com !ok nos jobs cobre os caminhos de cancelamento e esvaziamento.wg.Wait() antes de sair confirma que os workers pararam.Relacionado: Evitando Vazamentos de Goroutine e Deadlocks de Canal - regras de propriedade
Simule I/O paralelo com cancelamento compartilhado no primeiro erro.
package main
import (
"context"
"errors"
"fmt"
"golang.org/x/sync/errgroup"
)
func fetch(ctx context.Context, name string, fail bool) error {
if fail {
return fmt.Errorf("%s unavailable", name)
}
select {
case <-ctx.Done():
return ctx.Err()
default:
fmt.Println("ok", name)
return nil
}
}
func main() {
g, ctx := errgroup.WithContext(context.Background())
g.Go(func() error { return fetch(ctx, "users", false) })
g.Go(func() error { return fetch(ctx, "billing", true) })
if err := g.Wait(); err != nil {
fmt.Println("abort:", err)
}
}ctx para os irmãos ainda em execução.http.NewRequestWithContext em serviços reais.g.SetLimit(n) quando o fan-out deve respeitar cotas downstream.Relacionado: Propagação de Cancelamento em Handlers HTTP - ctx com escopo de requisição
O balde de tokens limita a velocidade com que os jobs entram no pool.
package main
import (
"context"
"fmt"
"time"
"golang.org/x/time/rate"
)
func main() {
lim := rate.NewLimiter(rate.Every(100*time.Millisecond), 1)
ctx := context.Background()
for i := 1; i <= 5; i++ {
if err := lim.Wait(ctx); err != nil {
panic(err)
}
fmt.Println("emit", i, time.Now().Format("15:04:05.000"))
}
}Every(d) define a taxa constante; o burst permite picos curtos.Wait bloqueia; Allow não bloqueia para caminhos de descarte de carga.ctx da requisição em Wait para que o cancelamento pare um produtor limitado.Relacionado: Limitação de Taxa e Backpressure - semáforos vs balde de tokens
Versões da Stack: Esta página foi escrita para Go 1.26.x (padrão GC Green Tea, go fix modernizers - verifique o patch na compilação), chi (última versão - verifique na compilação), gin (última versão - verifique na compilação), echo (última versão - verifique na compilação), google.golang.org/grpc (última versão - verifique na compilação), sigs.k8s.io/controller-runtime (última versão - verifique na compilação), kubebuilder (última versão - verifique na compilação), tinygo (última versão - verifique os alvos de placa na compilação), wazero (última versão - verifique na compilação) e golangci-lint (última versão - verifique o conjunto de linters na compilação).
Revisado por Chris St. John·Última atualização: 18 de jul. de 2026