Fácil Go
Iniciando uma goroutine simples
Enunciado
Escreva um programa que inicie uma goroutine para imprimir "Olá da goroutine!" e, em seguida, imprima "Olá da main!" na função principal. Use sync.WaitGroup para garantir que a goroutine termine antes do programa encerrar.
Requisitos
- Usar
go func()para iniciar a goroutine. - Usar
sync.WaitGroupcomAdd(1),Done()eWait(). - A saída deve conter as duas mensagens, em qualquer ordem, mas a main deve esperar.
Código inicial
package main
import (
"fmt"
"sync"
)
func main() {
// TODO: criar WaitGroup, iniciar goroutine e esperar
}
Saída esperada
Olá da goroutine!
Olá da main!
Ver dica
Lembre-se de chamar wg.Add(1) antes de iniciar a goroutine e wg.Done() dentro dela (pode usar defer).
Mostrar solução
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(1) // registra uma goroutine
go func() {
defer wg.Done() // decrementa o contador ao terminar
fmt.Println("Olá da goroutine!")
}()
wg.Wait() // espera a goroutine terminar
fmt.Println("Olá da main!")
}
Passo a passo
- Declaramos
var wg sync.WaitGrouppara coordenar a execução. wg.Add(1)informa que uma nova goroutine será executada.go func() { ... }()inicia a goroutine anônima imediatamente.- Dentro da goroutine,
defer wg.Done()garante que o contador seja decrementado ao final, mesmo se ocorrer um panic. - A goroutine imprime a mensagem.
wg.Wait()bloqueia a main até que o contador chegue a zero.- Por fim, a main imprime sua mensagem.
Por que funciona
WaitGroup é um contador seguro para concorrência. Add(1) aumenta o contador, Done() diminui e Wait() bloqueia até que ele seja zero. Assim, a main não termina antes da goroutine, evitando que o programa encerre prematuramente.
Erros comuns
- Esquecer
wg.Add(1):wg.Wait()retorna imediatamente e a goroutine pode não rodar. Corrija chamandoAddantes dogo. - Chamar
wg.Done()fora da goroutine: pode decrementar antes da hora. Usedeferdentro da função. - Copiar o
WaitGroup(ex.: passar por valor): causa comportamento indefinido. Sempre passe por ponteiro ou use a variável original.
Outra forma de resolver
Usar um canal para sincronizar:
done := make(chan struct{})
go func() {
fmt.Println("Olá da goroutine!")
close(done)
}()
<-done
fmt.Println("Olá da main!")
Canais são preferíveis quando há troca de dados, não apenas sincronização.
Saída esperada
Olá da goroutine!
Olá da main!