36/100 Dias de Golang - Select Goroutines
Table of Contents
#
Select Goroutines
Fiz vários posts falando sobre goroutines:
- 17/100 Dias de Golang - Concorrência e Goroutines
- 18/100 Dias de Golang - Goroutines, WaitGroup, Race condition e Mutex
- 19/100 Dias de Golang - Channels
- 20/100 Dias de Golang - Exemplo de goroutines, mutex e channels
Segundo o roadmap.sh do Golang, não fiz um post falando sobre Select, vamos corrigir isso então.
Se você já usou uma linguagem que possui switch
, vai notar que select funciona de maneira semelhante, mas é voltado para a comunicação entre canais. O select
permite que uma goroutine espere em múltiplos canais ao mesmo tempo. Ele escolhe um dos casos cujo canal está pronto para receber ou enviar e executa o bloco correspondente. Veja a sintaxe básica:
select {
case msg1 := <-ch1:
fmt.Println("Recebido de ch1:", msg1)
case msg2 := <-ch2:
fmt.Println("Recebido de ch2:", msg2)
default:
fmt.Println("Nenhum canal pronto")
}
Veja esse exemplo mais completo:
package main
import (
"fmt"
"math/rand"
"time"
)
func produtor(nome string, ch chan<- string) {
for {
tempo := time.Duration(rand.Intn(1000)) * time.Millisecond
time.Sleep(tempo)
ch <- fmt.Sprintf("Mensagem de %s após %v", nome, tempo)
}
}
func main() {
ch1 := make(chan string)
ch2 := make(chan string)
go produtor("produtor1", ch1)
go produtor("produtor2", ch2)
for i := 0; i < 5; i++ {
select {
case msg := <-ch1:
fmt.Println("Recebido:", msg)
case msg := <-ch2:
fmt.Println("Recebido:", msg)
}
}
}
Veja a saída:
Recebido: Mensagem de produtor2 após 425ms
Recebido: Mensagem de produtor2 após 63ms
Recebido: Mensagem de produtor1 após 858ms
Recebido: Mensagem de produtor1 após 306ms
Recebido: Mensagem de produtor2 após 947ms
A função produtor
executa em um loop infinito, gerando mensagens personalizadas com o nome do produtor e o tempo de espera, que varia aleatoriamente entre 0 e 1000 milissegundos.
func produtor(nome string, ch chan<- string) {
for {
tempo := time.Duration(rand.Intn(1000)) * time.Millisecond
time.Sleep(tempo)
ch <- fmt.Sprintf("Mensagem de %s após %v", nome, tempo)
}
}
Na função main, são criados dois canais (ch1 e ch2) e iniciadas duas goroutines produtoras em paralelo.
ch1 := make(chan string)
ch2 := make(chan string)
go produtor("produtor1", ch1)
go produtor("produtor2", ch2)
Usamos o select para escutar ambos os canais simultaneamente, imprimindo as primeiras 5 mensagens recebidas, independentemente de qual produtor as enviou.
for i := 0; i < 5; i++ {
select {
case msg := <-ch1:
fmt.Println("Recebido:", msg)
case msg := <-ch2:
fmt.Println("Recebido:", msg)
}
}
Podemos também usar o select
para definir um tempo limite de espera, esperar um request de uma API externa por no máximo 3 segundos e caso demore mais que isso vou tratar esse “erro”.
select {
case resp := <-responseChan:
// processa resposta
case <-time.After(3 * time.Second):
// timeout
}