Noções Básicas de Concorrência
10 exemplos para você começar com Concorrência - 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 - 7 básicos e 3 intermediários.
mkdir conc && cd conc && go mod init example.com/conc.main.go e execute com go run ..go test -race ./... quando os exemplos usarem estado compartilhado.Comece o trabalho concorrentemente com go.
package main
import (
"fmt"
"time"
)
func main() {
go func() {
fmt.Println("da goroutine")
}()
time.Sleep(100 * time.Millisecond) // espera para que a saída apareça antes de sair
fmt.Println("da main")
}go agenda a função em uma nova goroutine; ela retorna imediatamente.main pode sair antes que a goroutine imprima.sync.WaitGroup ou canais em vez de time.Sleep em código real.Relacionado: Concorrência em Go: Goroutines e Canais Primeiro - Modelo mental CSP
Remetente e receptor se encontram no canal.
package main
import "fmt"
func main() {
ch := make(chan string)
go func() { ch <- "ping" }()
msg := <-ch
fmt.Println(msg)
}make(chan string) cria um canal não bufferizado - capacidade zero.Relacionado: Canais: Regras de Buffer, Não Buffer e Fechamento - regras de buffer e fechamento
Desacople remetente e receptor até a capacidade.
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch, <-ch)
}make(chan int, 2) permite dois envios sem um receptor esperando.Relacionado: Canais: Regras de Buffer, Não Buffer e Fechamento - quando usar buffer
Espere um lote de goroutines terminar.
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
for i := 1; i <= 3; i++ {
wg.Add(1)
go func(n int) {
defer wg.Done()
fmt.Println("worker", n)
}(i)
}
wg.Wait()
fmt.Println("done")
}Add antes de go, Done em um defer dentro do worker.Wait bloqueia até que o contador retorne a zero.Relacionado: sync.Mutex, RWMutex e WaitGroup - detalhes do WaitGroup
Sinalize a conclusão fechando do remetente.
package main
import "fmt"
func main() {
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for v := range ch {
fmt.Println(v)
}
}range esvazia até que o canal seja fechado e vazio.close; enviar em um canal fechado causa pânico.ok == false na forma de dois valores.Relacionado: Canais: Regras de Buffer, Não Buffer e Fechamento - regras de propriedade
select espera por operações de canal (aqui, um único recebimento).
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
go func() {
time.Sleep(50 * time.Millisecond)
ch <- "ready"
}()
select {
case msg := <-ch:
fmt.Println(msg)
}
}select bloqueia até que um caso possa prosseguir.default para comportamento não bloqueante.Relacionado: Instrução select e Casos Padrão - padrões de multiplexação
Quando múltiplas goroutines mutam dados, bloqueie-os.
package main
import (
"fmt"
"sync"
)
func main() {
var mu sync.Mutex
count := 0
var wg sync.WaitGroup
for i := 0; i < 100; i++ {
wg.Add(1)
go func() {
defer wg.Done()
mu.Lock()
count++
mu.Unlock()
}()
}
wg.Wait()
fmt.Println(count)
}Mutex serializa seções críticas - aqui count++.Lock com Unlock; defer mu.Unlock() após Lock é idiomático.-race para capturar locks ausentes.Relacionado: sync.Mutex, RWMutex e WaitGroup - disciplina de lock
Evite esperar para sempre por trabalho lento.
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan string)
select {
case msg := <-ch:
fmt.Println(msg)
case <-time.After(100 * time.Millisecond):
fmt.Println("timeout")
}
}time.After retorna um canal que dispara após a duração.context.Context em vez de sleeps ad-hoc.Relacionado: Instrução select e Casos Padrão - receitas de timeout
Um produtor, uma goroutine consumidora.
package main
import "fmt"
func main() {
jobs := make(chan int, 5)
done := make(chan struct{})
go func() {
for j := range jobs {
fmt.Println("processado", j)
}
close(done)
}()
for i := 1; i <= 3; i++ {
jobs <- i
}
close(jobs)
<-done
}jobs permite que o worker range saia limpo.done sinaliza que o consumidor terminou - alternativa ao WaitGroup.Relacionado: Goroutines: Custo de Criação e Visão Geral do Agendamento - agendando muitos workers
Compile com -race para capturar acesso não sincronizado.
package main
import (
"sync"
"testing"
)
func TestCounter(t *testing.T) {
var wg sync.WaitGroup
n := 0
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
n++ // corrida: descomente mu do exemplo 7 para corrigir
}()
}
wg.Wait()
}go test -race - o detector de corrida relata acessos conflitantes.-race em CI para pacotes que usam goroutines.Relacionado: Detector de Corridas: Executando e Interpretando Saída - lendo a saída de corrida
Versões de Stack: Esta página foi escrita para Go 1.26.x (GC padrão Green Tea, modernizadores go fix - 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: 19 de jul. de 2026