Introdução
Ao trabalhar com concorrência na prática, a comunicação entre múltiplas Goroutines frequentemente se faz necessária. Por exemplo, em um cenário de microsserviço, você pode receber múltiplas mensagens e validá-las em um momento posterior no processo atual — sem precisar aguardar a conclusão da validação de uma mensagem antes de iniciar a próxima. Essa situação ocorre com frequência, e usar canais garante a comunicação entre múltiplas Goroutines rodando de forma concorrente.
Agora que você conhece o propósito dos Channels, podemos falar sobre dois tipos diferentes: Canais Unbuffered e Buffered.
Canais Unbuffered
Este tipo de canal não tem tamanho definido — sua capacidade é zero. Com capacidade zero, ele só permite que um valor seja enviado por vez. Se nenhuma Goroutine estiver disponível para ler dados do canal, será necessário aguardar até que a Goroutine conclua seu processo atual para acessar o próximo valor que está aguardando consumo.
Canais Buffered
Nos canais buffered, um tamanho é definido na criação. Canais buffered permitem que o remetente continue enviando valores sem precisar aguardar que cada um seja consumido, até que o buffer esteja cheio.
Diferença e caso de uso
A diferença entre eles é clara: canais buffered e unbuffered são criados na inicialização, definidos pelo tamanho especificado. Se um tamanho é especificado, o canal é buffered; caso contrário, é unbuffered. Canais buffered são tipicamente usados quando a sincronização imediata não é necessária. Canais unbuffered, por outro lado, são usados para comunicação imediata quando a ordem de processamento é crucial.
Exemplos
Buffered
Em canais buffered, as primeiras cinco interações são produzidas e armazenadas antes que a primeira seja consumida. Isso ocorre porque todos os dados são guardados no buffer, que foi definido como cinco neste exemplo. O tamanho do canal foi definido como cinco no início do código — portanto, não foi necessário aguardar o consumo da primeira mensagem para armazenar mais dados. Essa configuração evita que os processos sejam bloqueados na mensagem inicial.
Loading...
- Saída
Sending 1
Sending 2
Sending 3
Sending 4
Sending 5
All values sent to the buffered channel
Starting to consume values from the buffered channel
Received 1
Received 2
Received 3
Received 4
Received 5Unbuffered
Em canais unbuffered, tudo muda. Neste caso, cada interação é consumida imediatamente ao ser enviada, pois não há buffer. Por isso, cada interação é consumida assim que é enviada. Após um valor ser processado, o próximo segue, e essa sequência continua até que todas as interações sejam concluídas.
Loading...
- Saída
Sending 1
Received 1
Sent 1
Sending 2
Received 2
Sent 2
Sending 3
Received 3
Sent 3
Sending 4
Received 4
Sent 4
Sending 5
Received 5
Sent 5Considerações Finais
Levando em conta o que foi apresentado, a diferença entre eles é clara. Em resumo, canais unbuffered são usados quando a sincronização imediata entre goroutines é necessária, especialmente para evitar condições de corrida que poderiam gerar inconsistências. Canais buffered são preferíveis quando se quer evitar o bloqueio de processos, pois podem melhorar a eficiência ao reduzir os bloqueios no canal. Se o processamento com atraso é aceitável, canais buffered funcionam bem; caso contrário, canais unbuffered são a melhor escolha.