Istruzione select
Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 62 di 107.
L'istruzione select consente a una goroutine di attendere contemporaneamente più operazioni sui canali. È simile a un'istruzione switch, ma ogni caso prevede un invio o una ricezione su un canale. Quando più canali sono pronti, select ne sceglie uno a caso.
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)
}
}Senza select, ricevere da ch1 bloccherebbe finché non arrivano dati, rischiando di perdere i dati su ch2. Con select, viene gestito per primo il canale che riceve i dati.
Il caso default rende select non bloccante. Viene eseguito immediatamente se nessun canale è pronto:
select {
case msg := <-messages:
fmt.Println("Received:", msg)
default:
fmt.Println("No message available")
}Uno schema comune combina select con i timeout usando time.After, che restituisce un canale che riceve un valore dopo la durata specificata:
select {
case result := <-ch:
fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}Questo impedisce al tuo programma di attendere per sempre quando un'operazione sul canale potrebbe non completarsi mai.
Sfida
FacileCreiamo un monitor di servizi che usa l’istruzione select per gestire più origini dati simultanee. Il monitor ascolterà contemporaneamente diversi canali di servizio e risponderà in modo appropriato quando arrivano dati o quando non sono disponibili aggiornamenti.
Organizzerai il codice in due file:
monitor.go: definisci la logica di monitoraggio dei servizi, gestendo i canali conselect.Crea una struct
ServiceUpdatecon i campiName(string) eStatus(string).Implementa una funzione
Monitorche accetta tre canali:primary chan ServiceUpdate,backup chan ServiceUpdateedone chan bool. Questa funzione deve usareselectper ascoltare contemporaneamente tutti e tre i canali:- Quando riceve da
primary: restituisce la stringa formattataPrimary: [Name] is [Status] - Quando riceve da
backup: restituisce la stringa formattataBackup: [Name] is [Status] - Quando riceve da
done: restituisceMonitoring stopped
Implementa una funzione
CheckStatusche accetta un singoloupdates chan ServiceUpdatee usaselectcon un casodefaultper eseguire un controllo non bloccante:- Se è disponibile un aggiornamento: restituisce
Update available: [Name] - Se non è disponibile alcun aggiornamento (caso default): restituisce
No updates pending
- Quando riceve da
main.go: configura i canali e mostra il comportamento diselectbloccante e non bloccante.Leggi dalla riga di input una modalità che determina quale scenario eseguire:
primary,backup,stopocheck.Per le modalità
primary,backupestop: leggi anche il nome e lo stato di un servizio. Crea i tre canali, avvia una goroutine che invia i dati al canale appropriato in base alla modalità, quindi chiamaMonitore stampa il risultato.Per la modalità
check: leggi il nome e lo stato di un servizio, oltre a un flag (sendonosend) che indica se inviare i dati prima del controllo. Crea un canale con buffer e capacità 1. Se il flag èsend, invia un aggiornamento al canale prima di chiamareCheckStatus. Stampa il risultato diCheckStatus.
Verranno forniti i seguenti input:
- Riga 1: modalità (
primary,backup,stopocheck) - Riga 2: nome del servizio
- Riga 3: stato del servizio
- Riga 4 (solo per la modalità
check):sendonosend
Ad esempio, dato:
primary
Database
healthyL’output dovrebbe essere:
Primary: Database is healthyE dato:
check
Cache
active
nosendL’output dovrebbe essere:
No updates pendingProvalo tu
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: Gestire le diverse modalità: "primary", "backup", "stop", "check"
// Per le modalità "primary", "backup", "stop":
// - Crea tre canali: primary, backup, done
// - Avvia una goroutine che invia i dati al canale appropriato
// - Chiama Monitor e stampa il risultato
// Per la modalità "check":
// - Leggi il flag aggiuntivo ("send" o "nosend")
// - Crea un canale con buffer di capacità 1
// - Se il flag è "send", invia un aggiornamento al canale
// - Chiama CheckStatus e stampa il risultato
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti di OOP in Go
File esterniWorkspace e moduli GoPacchetti e importazioniNomi esportati e non esportatiIntroduzione all’OOP in GoGli struct come classiDefinire metodi sugli structReceiver con puntatore vs receiver con valoreInizializzazione degli structFunzioni costruttriciRiepilogo - Calcolatrice semplice4Interfacce
Introduzione alle interfacceImplementazione implicitaL’interfaccia come contrattoInterfaccia vuota (any)Asserzione di tipoSwitch sul tipoComposizione di interfacceInterfacce Stringer ed ErrorRipasso - Calcolatore di forme7Incapsulamento
Campi esportati e non esportatiIncapsulamento a livello di packageMetodi Getter e SetterNascondimento delle informazioni in GoRiepilogo - Registri degli studenti10Tipi generici (Go 1.18+)
Introduzione ai tipi genericiParametri di tipoVincoli di tipoStruct genericheSoluzione alternativa per i metodi genericiRiepilogo - Collezione generica13Modelli di progettazione Parte 1
Introduzione ai modelli di progettazioneModello SingletonModello FactoryModello Abstract FactoryModello ObserverModello Strategy2Approfondimento su tipi e struct
Tipi di base e compostiDefinizioni di tipi personalizzatiTag delle structStruct anonimeStruct annidateValori zero e predefinitiRipasso - Rubrica5Composizione invece dell'ereditarietà
Perché Go non ha l'ereditarietàFondamenti dell'embedding delle structPromozione dei metodiEmbedding di più structEmbedding e aggregazione a confrontoMascheramento dei metodi embeddedRiepilogo: gerarchia dei dipendenti8Gestione degli errori e OOP
L'interfaccia errorTipi di errore personalizzatiWrapping degli errori (fmt.Errorf)Errori sentinellaerrors.Is() ed errors.As()Panic, Defer e RecoverRiepilogo - Parser di file11Libreria standard e OOP
io.Reader e io.Writersort.InterfaceInterfaccia fmt.Stringerencoding/json con le structInterfaccia http.HandlerRipasso - modelli REST API14Modelli di progettazione – Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeMiddleware come Decorator3Puntatori e memoria
Concetti base dei puntatori in GoPuntatori a structPassaggio per valore vs per riferimentoLa funzione new()Garbage collection in GoRiepilogo - Costruttore di liste concatenate6Polimorfismo in Go
Polimorfismo tramite interfacceDuck typing in GoRegole di soddisfacimento delle interfacceCollezioni polimorficheIniezione delle dipendenzeRiepilogo - Elaboratore di pagamenti9Concorrenza e OOP
Basi delle goroutineCanali e comunicazioneCanali bufferizzati vs non bufferizzatiIstruzione selectsync.Mutex e sync.RWMutexsync.WaitGroupProgettazione di struct thread-safeRiepilogo: worker poolEsercitati da solo: Compilatore Go online