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)