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.
Desafio
FácilVamos 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
ServiceUpdatecom os camposName(string) eStatus(string).Implemente uma função
Monitorque receba três canais:primary chan ServiceUpdate,backup chan ServiceUpdateedone chan bool. Essa função deve usarselectpara escutar os três canais simultaneamente:- Ao receber de
primary: retorne a string formatadaPrimary: [Name] is [Status] - Ao receber de
backup: retorne a string formatadaBackup: [Name] is [Status] - Ao receber de
done: retorneMonitoring stopped
Implemente uma função
CheckStatusque receba um únicoupdates chan ServiceUpdatee useselectcom um casodefaultpara 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
- Ao receber de
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,stopoucheck.Para os modos
primary,backupestop: 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 chameMonitore imprima o resultado.Para o modo
check: leia um nome e um status de serviço, além de uma flag (sendounosend) que indique se os dados devem ser enviados antes da verificação. Crie um canal com buffer e capacidade 1. Se a flag forsend, envie uma atualização para o canal antes de chamarCheckStatus. Imprima o resultado deCheckStatus.
As entradas a seguir serão fornecidas:
- Linha 1: modo (
primary,backup,stopoucheck) - Linha 2: nome do serviço
- Linha 3: status do serviço
- Linha 4 (somente para o modo
check):sendounosend
Por exemplo, considerando:
primary
Database
healthySua saída deve ser:
Primary: Database is healthyE considerando:
check
Cache
active
nosendSua saída deve ser:
No updates pendingExperimente 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
}
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
1Fundamentos de OOP em Go
Arquivos ExternosWorkspace e Módulos do GoPacotes e ImportsNomes Exportados vs. Não ExportadosIntrodução à OOP em GoStructs como ClassesDefinindo Métodos em StructsReceptores de Ponteiro vs. de ValorInicialização de StructsFunções ConstrutorasRecapitulação — Calculadora Simples4Interfaces
Introdução às InterfacesImplementação ImplícitaInterface como ContratoInterface Vazia (any)Asserção de TipoSwitch de TipoComposição de InterfacesInterfaces Stringer e ErrorRecapitulação - Calculadora de Formas7Encapsulamento
Campos Exportados vs. Não ExportadosEncapsulamento no Nível de PacoteMétodos Getters e SettersOcultação de Informações em GoRecapitulação - Registros de Alunos10Genéricos (Go 1.18+)
Introdução aos genéricosParâmetros de tipoRestrições de tipoStructs genéricasAlternativa para métodos genéricosRecapitulação - Coleção genérica13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão Abstract FactoryPadrão ObserverPadrão Strategy2Tipos e Structs em Profundidade
Tipos Básicos e CompostosDefinições de Tipos PersonalizadosTags de StructStructs AnônimasStructs AninhadasValores Zero e PadrõesRecapitulação - Livro de Contatos5Composição em vez de herança
Por que Go não tem herançaNoções básicas de incorporação de structsPromoção de métodosIncorporação de várias structsIncorporação vs agregaçãoOcultação de métodos incorporadosRecapitulação - Hierarquia de funcionários8Tratamento de Erros e OOP
A interface errorTipos de Erro PersonalizadosEncapsulamento de Erros (fmt.Errorf)Erros Sentinelaerrors.Is() e errors.As()Panic, Defer e RecoverRecapitulação - Analisador de Arquivos3Ponteiros e Memória
Fundamentos de Ponteiros em GoPonteiros para StructsPassagem por Valor vs. ReferênciaA Função new()Coleta de Lixo em GoRecapitulação - Construtor de Lista Ligada6Polimorfismo em Go
Polimorfismo via InterfacesDuck Typing em GoRegras de Satisfação de InterfacesColeções PolimórficasInjeção de DependênciasRecapitulação - Processador de Pagamentos9Concorrência e OOP
Fundamentos de GoroutinesCanais e comunicaçãoCanais com e sem bufferInstrução selectsync.Mutex e sync.RWMutexsync.WaitGroupDesign de structs thread-safeRevisão - Worker PoolPratique por conta própria: Compilador de Go online