Desafio Go
Pipeline concorrente com detecção de corrida
Enunciado
Implemente um pipeline com três estágios: (1) gerar números de 1 a 10 em um canal; (2) dobrar cada número em goroutines separadas; (3) somar os resultados. Use sync.WaitGroup para sincronizar e go run -race para verificar ausência de data races. O resultado final deve ser a soma dos dobros (110).
Requisitos
- Criar três funções:
gerar,dobraresomar. - Usar canais para comunicação entre estágios.
- Usar
sync.WaitGrouppara esperar as goroutines de dobra. - O programa deve rodar sem avisos com
go run -race. - Imprimir a soma final igual a 110.
Código inicial
package main
import (
"fmt"
)
func main() {
// TODO: implementar pipeline com canais, goroutines e WaitGroup
}
Saída esperada
Soma: 110
Ver dica
Use um canal de entrada, um canal de saída e um WaitGroup para as goroutines que dobram. Feche o canal de saída após o Wait.
Mostrar solução
package main
import (
"fmt"
"sync"
)
func gerar(nums []int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for _, n := range nums {
out <- n
}
}()
return out
}
func dobrar(in <-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for i := 0; i < 3; i++ { // 3 workers
wg.Add(1)
go func() {
defer wg.Done()
for n := range in {
out <- n * 2
}
}()
}
go func() {
wg.Wait()
close(out)
}()
return out
}
func somar(in <-chan int) int {
total := 0
for n := range in {
total += n
}
return total
}
func main() {
nums := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
c1 := gerar(nums)
c2 := dobrar(c1)
total := somar(c2)
fmt.Println("Soma:", total)
}
Passo a passo
gerarcria um canalout, inicia uma goroutine que envia os números e fecha o canal ao terminar.dobrarcria um canaloute umWaitGroup.- Iniciamos 3 workers (goroutines) que leem de
in, dobram o valor e enviam paraout. - Cada worker usa
defer wg.Done()para decrementar o contador ao final. - Uma goroutine separada espera o
WaitGroupe fechaoutapós todos os workers terminarem. somarconsomeoutaté o canal ser fechado, acumulando o total.- A main chama os estágios em sequência e imprime o resultado.
Por que funciona
O pipeline usa canais para passar dados entre estágios, evitando compartilhamento direto de memória. O WaitGroup coordena os workers de dobra: só fecha o canal de saída quando todos terminam. Como não há acesso concorrente a variáveis compartilhadas sem sincronização, o -race não detecta problemas. A soma é feita sequencialmente no estágio final, garantindo o resultado correto.
Erros comuns
- Esquecer de fechar o canal de saída:
somarfica bloqueado para sempre (deadlock). Corrija comclose(out)apóswg.Wait(). - Fechar o canal antes de todos os workers terminarem: panic por envio em canal fechado. Use a goroutine que espera o
WaitGroup. - Não usar
WaitGroupe fechar o canal imediatamente: perda de dados. Sincronize corretamente.
Outra forma de resolver
Usar sync/atomic para a soma, mas exigiria compartilhar a variável entre goroutines. A abordagem com canais é mais idiomática e segura.
Saída esperada
Soma: 110