Pular para o conteúdo principal

victorstein.dev

19/100 Dias de Golang - Channels

Table of Contents

# Channels

Os channels nos permitem segurança para comunicação entre as threads. Extraído do livro A Linguagem de Programação Go:

Um canal é um sistema de comunicação que permite a uma gorrotina enviar valores para outra gorrotina E como tudo é fortemente tipado no Go, cada canal possui um tipo, veja como é simples criar um channel:

ch := make(chan int)

Com canais podemos fazer duas operações, enviar e receber. Vamos fazer um exemplo bem simples. Criar uma goroutine que envia uma informação para um canal e vamos printar esse valor fora dessa goroutine

package main

func cria_texto(ch chan string) {

	ch <- "Texto criado na goroutine cria_text"

}

func main() {

	ch := make(chan string)

	go cria_texto(ch)

	msg := <-ch

	println(msg)

}

Veja que na linha ch <- "Texto criado na goroutine cria_text" estamos enviando dados para o channel com o operador <-. E depois na função main recebemos esse dados msg := <-ch, veja o que operador é o mesmo <-, o que mudar é que na operação de recepção o <- antecede o a variável referente ao canal.

Sugiro criarmos um exemplo mais avançado, com uma função geradora de dados e outra consumidora, para investigarmos a sincronização dessas informações.

package main

import (
	"fmt"
	"math/rand"
)

func producer(ch chan int) {

	for i := 0; i < 10; i++ {

		ch <- rand.Intn(100)
	}

}

func consumer(ch chan int) {
	for i := range ch {
		fmt.Printf("Recebido %d\n", i)
	}
}
func main() {

	ch := make(chan int)

	go producer(ch)
	consumer(ch)
}

A função producer cria número aleatório e envia para o canal, enquanto a consumer lê e imprime os valores recebidos. Se você rodar esse programa irá ver um erro:

Recebido 48
Recebido 82
Recebido 15
Recebido 84
Recebido 16
Recebido 45
Recebido 29
Recebido 68
Recebido 0
Recebido 61
fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan receive]:
main.consumer(0xc000096070)

O erro de deadlock ocorre quando goroutines ficam esperando indefinidamente por operações em um canal. Nesse caso a consumer está esperando um dado que nunca vai ser gerado. Para isso podemos usar o close, que serve para fechar o canal depois que o producer finalizar.

func producer(ch chan int) {

	for i := 0; i < 10; i++ {

		ch <- rand.Intn(100)
	}
	close(ch)

}

# Channels Directions

Podemos definir o “tipo” do nosso channel, definindo ele como um sender, receiver ou ambos. A vantagem de fazer isso é que facilita a leitura do código, logo que vemos a função já sabemos qual o tipo do channel, ajuda o compilador a detectar erros e melhora a segurança de tipos da aplicação. Veja como fazer isso:

Envia:

func sendData(ch chan<- int)

Recebe:

func receiveData(ch <-chan int)

Bidirecional

func sendReceiveData(ch chan int)