Menu
Coddy logo textTech

Instrução select

Parte da seção Programação Orientada a Objetos do Journey de GO da Coddy. Lição 62 de 107.

A instrução select permite que uma goroutine aguarde simultaneamente várias operações de canal. É como uma instrução switch, mas cada caso envolve um envio ou recebimento em um canal. Quando vários canais estão prontos, select escolhe um deles aleatoriamente.

func main() {
    ch1 := make(chan string)
    ch2 := make(chan string)
    
    go func() { ch1 <- "from channel 1" }()
    go func() { ch2 <- "from channel 2" }()
    
    select {
    case msg1 := <-ch1:
        fmt.Println(msg1)
    case msg2 := <-ch2:
        fmt.Println(msg2)
    }
}

Sem select, receber de ch1 bloquearia até que os dados chegassem, possivelmente perdendo dados em ch2. Com select, o canal que receber dados primeiro será tratado.

O caso default torna select não bloqueante. Ele é executado imediatamente se nenhum canal estiver pronto:

select {
case msg := <-messages:
    fmt.Println("Received:", msg)
default:
    fmt.Println("No message available")
}

Um padrão comum combina select com timeouts usando time.After, que retorna um canal que recebe um valor após a duração especificada:

select {
case result := <-ch:
    fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
    fmt.Println("Timeout!")
}

Isso evita que seu programa fique esperando para sempre quando uma operação de canal talvez nunca seja concluída.

challenge icon

Desafio

Fácil

Vamos criar um monitor de serviços que usa a instrução select para lidar com várias fontes de dados simultâneas. Seu monitor escutará diferentes canais de serviço simultaneamente e responderá adequadamente quando os dados chegarem ou quando não houver atualizações disponíveis.

Você organizará seu código em dois arquivos:

  • monitor.go: defina sua lógica de monitoramento de serviços com manipulação de canais baseada em select.

    Crie uma struct ServiceUpdate com os campos Name (string) e Status (string).

    Implemente uma função Monitor que receba três canais: primary chan ServiceUpdate, backup chan ServiceUpdate e done chan bool. Essa função deve usar select para escutar os três canais simultaneamente:

    • Ao receber de primary: retorne a string formatada Primary: [Name] is [Status]
    • Ao receber de backup: retorne a string formatada Backup: [Name] is [Status]
    • Ao receber de done: retorne Monitoring stopped

    Implemente uma função CheckStatus que receba um único updates chan ServiceUpdate e use select com um caso default para realizar uma verificação não bloqueante:

    • Se uma atualização estiver disponível: retorne Update available: [Name]
    • Se nenhuma atualização estiver disponível (caso default): retorne No updates pending
  • main.go: configure os canais e demonstre o comportamento bloqueante e não bloqueante de select.

    Leia um modo da entrada que determine qual cenário executar: primary, backup, stop ou check.

    Para os modos primary, backup e stop: leia também um nome e um status de serviço. Crie os três canais, inicie uma goroutine que envie dados para o canal apropriado com base no modo, depois chame Monitor e imprima o resultado.

    Para o modo check: leia um nome e um status de serviço, além de uma flag (send ou nosend) que indique se os dados devem ser enviados antes da verificação. Crie um canal com buffer e capacidade 1. Se a flag for send, envie uma atualização para o canal antes de chamar CheckStatus. Imprima o resultado de CheckStatus.

As entradas a seguir serão fornecidas:

  • Linha 1: modo (primary, backup, stop ou check)
  • Linha 2: nome do serviço
  • Linha 3: status do serviço
  • Linha 4 (somente para o modo check): send ou nosend

Por exemplo, considerando:

primary
Database
healthy

Sua saída deve ser:

Primary: Database is healthy

E considerando:

check
Cache
active
nosend

Sua saída deve ser:

No updates pending

Experimente você mesmo

package main

import (
	"fmt"
)

func main() {
	var mode string
	fmt.Scanln(&mode)

	var serviceName string
	fmt.Scanln(&serviceName)

	var serviceStatus string
	fmt.Scanln(&serviceStatus)

	// TODO: Lidar com diferentes modos: "primary", "backup", "stop", "check"
	
	// Para os modos "primary", "backup", "stop":
	// - Crie três canais: primary, backup, done
	// - Lance uma goroutine que envia dados para o canal apropriado
	// - Chame Monitor e imprima o resultado
	
	// Para o modo "check":
	// - Leia o flag adicional ("send" ou "nosend")
	// - Crie um canal bufferizado com capacidade 1
	// - Se o flag for "send", envie uma atualização para o canal
	// - Chame CheckStatus e imprima o resultado
	
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Compilador de Go online