Channels por baixo dos panos

antiduhring

Mateus Vinícius

Posted on November 25, 2023

Channels por baixo dos panos

Channels são canais de comunicação e sincronização entre goroutines. A comunicação é feita através do envio de dados entre goroutines e a sincronização é feita pausando e retomando o processamento de uma goroutine quando necessário.

Podemos criar uma nova channel, com o seguinte código:

ch := make(chan Task, 3)
Enter fullscreen mode Exit fullscreen mode

O tipo chan Task significa que estamos criando uma channel que envia e recebe um dado de tipo Task, enquanto o parâmetro 3 representa a quantidade de dados que a channel pode guardar ao mesmo tempo na sua fila, iremos explorar o que isso significa muito em breve.

Por debaixo dos panos o valor da variável ch passa a ser um ponteiro para uma estrutura de dados chamada hchan, que é nada mais do que uma struct com 4 propriedades principais: buffer, sendx, recvx e lock. Cada propriedade possui um papel fundamental no funcionamento das channels.

O buffer é uma fila que guarda cópias dos dados enviados para a channel. Quando uma goroutine envia um dado para uma channel, o buffer armazena e mantém um cópia desse dado - chamamos esse processo de enqueue - e, quando uma goroutine recebe esse dado, ele é removido do buffer e uma cópia fica com a goroutine que o consome - esse processo chamamos de dequeue.

Sendx representa o índice do dado sendo enviado para a fila. No nosso exemplo acima de uma fila com 3 elementos, se uma goroutine envia o primeiro dado para a channel o sendx passa a ser 1, se envia mais outro o sendx passa a ser 2, se envia mais outro o sendx passa a ser...0. Essa é a definição de uma fila circular, pois o último elemento se conecta ao primeiro. O valor do sendx seria zero porque o próximo elemento depois do terceiro é o primeiro, portanto se a fila está cheia - já possui 3 elementos - e eventualmente o primeiro elemento da fila for removido, quando uma goroutine enviar para a channel um novo dado, ele ficará guardado no índice 1 - e ai o valor do sendx volta a ser 1 - e assim sucessivamente, de forma circular.

Recvx funciona da mesma forma que a propriedade sendx, mas é referente ao índice do dado sendo recebido por uma goroutine.

Lock consiste em um mutex, que é um tipo primitivo de dado usado para evitar race condition - ou seja, evitar que diferentes threads manipulem o mesmo dado compartilhado, no caso a channel, de foma simultânea, causando comportamentos inesperados ou corrupção de dados. Se duas goroutines tentarem fazem operações simultâneas na mesma channel apenas uma conseguirá o lock, e a outra deverá aguardar o unlock da primeira para realizar sua própria operação.

Podemos visualizar o fluxo de funcionamento de uma channel enquanto fila circular com o diagram criado por @akankshadokania.

Diagrama mostrando o funcionamento de uma channel

Um ponto importante que pode ser levantado é: Já que a fila circular possui um tamanho fixo de quantidade de elementos que podem ser salvos ao mesmo tempo, o que acontece se uma goroutine enviar mais um dado para a channel que já está cheia?

Usando nossa channel de 3 elementos como exemplo, imaginando que ele já possui 3 Tasks no buffer, o sendx e recvx seriam ambos 0 e o runtime do Go, sabendo que o índice 0 do buffer ainda está ocupado, bloquearia a execução da goroutine que tentou enviar o dado para a channel e apenas desbloquearia quando o recvx passasse a ser 1, ou seja, quando o primeiro elemento fosse removido da fila, assim permitindo o envio do dado para a channel.

Portanto channels são uma ferramenta poderosa por possuir essas características interessantes: São goroutine-safe, ou seja, possuem a capacidade de lidar com múltiplas goroutines sem levar a problemas de race condition; Possuem capacidade de salvar dados, como vimos no ponto sobre a propriedade buffer; Possui semântica FIFO - First In First Out -, ou seja, a fila do buffer recebe e envia os dados em ordem; Podem enviar dados entre goroutines e podem bloquear/desbloquear a execução de goroutines, dependendo da situação.

💖 💪 🙅 🚩
antiduhring
Mateus Vinícius

Posted on November 25, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Channels por baixo dos panos
webdev Channels por baixo dos panos

November 25, 2023