Ícone do site Aprenda Golang

Boas práticas na utilização de goroutines e channels

Goroutines e channels são fundamentais para a programação concorrente em Go, proporcionando uma maneira eficiente de realizar tarefas simultâneas. Caso você ainda não esteja tão familiarizado com goroutines e channels recomendo a leitura:

No entanto, embora a facilidade para se lidar com programação concorrente em Go seja grande, para garantir que o código seja eficiente e livre de erros, é essencial prestar atenção a alguns pontos.

1. Sincronização de Goroutines

Goroutines são leves e eficientes, mas sem uma sincronização adequada, elas podem levar a race conditions, ou seja, múltiplas goroutines acessam e modificam dados compartilhados simultaneamente. Utilize mecanismos como sync.Mutex ou sync.WaitGroup para garantir que as goroutines não entrem em conflito ao acessar dados compartilhados.

Exemplo com sync.WaitGroup:

var wg sync.WaitGroup
for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(i int) {
        defer wg.Done()
        fmt.Println(i)
    }(i)
}
wg.Wait()

2. Uso Adequado de Channels

Channels são utilizados para comunicação segura entre goroutines. No entanto, é crucial fechar os channels corretamente para evitar deadlocks e panics.

Em outras palavras, feche os channels somente quando todas as goroutines terminarem de enviar dados e nunca envie dados para um channel fechado, pois isso causará um panic.

ch := make(chan int)
go func() {
    for i := 0; i < 5; i++ {
        ch <- i
    }
    close(ch)
}()
for val := range ch {
    fmt.Println(val)
}

3. Evitando Deadlocks

Deadlocks ocorrem quando goroutines ficam bloqueadas indefinidamente esperando por operações que nunca ocorrerão. Para evitar deadlocks, certifique-se de que para cada operação de recebimento de dados (<-ch), existe uma operação de envio (ch <-) correspondente, e vice-versa.

Exemplo de potencial deadlock:

ch := make(chan int)
ch <- 1 // Goroutine principal bloqueada aqui, esperando que alguém receba o valor.
fmt.Println(<-ch) // Nunca alcançado.

Correção:

ch := make(chan int)
go func() {
    ch <- 1
}()
fmt.Println(<-ch)

4. Buffered Channels

Channels podem ser bufferizados ou não. Channels bufferizados permitem que você envie múltiplos valores antes que qualquer goroutine esteja pronta para recebê-los. Utilize buffered channels para reduzir a sobrecarga de sincronização e evitar bloqueios frequentes.

ch := make(chan int, 2)
go func() {
	ch <- 1
	ch <- 2
}
fmt.Println(<-ch)
fmt.Println(<-ch)

5. Evitando Variações Não Determinísticas

A execução concorrente pode levar a resultados não determinísticos. Portanto, testar e depurar código concorrente pode ser uma tarefa bem desafiadora.

Para ajudar na detecção de race conditions e outras questões relacionadas a concorrência, adicione a flag -race a execução dos seus testes (go test -race).

6. Limpeza Adequada

Goroutines que não são finalizadas corretamente podem levar a “vazamentos”, consumindo memória e outros recursos desnecessariamente. Utilize select com um canal de cancelamento para permitir que goroutines sejam finalizadas quando não são mais necessárias.

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

go func(ctx context.Context) {
    for {
        select {
        case <-ctx.Done():
            return
        default:
            // Realiza o trabalho da goroutine.
        }
    }
}(ctx)

Conclusão

Utilizar goroutines e channels de maneira eficiente e segura é fundamental para tirar o máximo proveito da concorrência em Go.

Para garantir que seu código seja robusto e livre de erros, preste sempre atenção aos pontos de sincronização, fechamento de channels, prevenção de deadlocks, uso de channels bufferizados, variações não determinísticas e limpeza adequada de goroutines.

Com essas práticas, você poderá desenvolver aplicações concorrentes poderosas e eficientes em Go.

Outra coisa que também pode te ajudar muito a desenvolver aplicações poderosas é fazer um dos nossos cursos ou imersões.

Até a próxima!


Faça parte da comunidade!

Receba os melhores conteúdos sobre Go, Kubernetes, arquitetura de software, Cloud e esteja sempre atualizado com as tendências e práticas do mercado.

Livros Recomendados

Abaixo listei alguns dos melhores livros que já li sobre GO.

Sair da versão mobile