Select-Anweisung
Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy. Lektion 62 von 107.
Die select-Anweisung ermöglicht es einer Goroutine, gleichzeitig auf mehrere Kanaloperationen zu warten. Sie ähnelt einer switch-Anweisung, aber jeder Fall umfasst das Senden oder Empfangen über einen Kanal. Wenn mehrere Kanäle bereit sind, wählt select einen davon zufällig aus.
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)
}
}Ohne select würde der Empfang von ch1 blockieren, bis Daten eintreffen, wodurch möglicherweise Daten auf ch2 verpasst werden. Mit select wird der Kanal behandelt, der zuerst Daten empfängt.
Der Fall default macht select nicht blockierend. Er wird sofort ausgeführt, wenn keine Kanäle bereit sind:
select {
case msg := <-messages:
fmt.Println("Received:", msg)
default:
fmt.Println("No message available")
}Ein häufig verwendetes Muster kombiniert select mit Zeitüberschreitungen mithilfe von time.After, das einen Kanal zurückgibt, der nach der angegebenen Dauer einen Wert empfängt:
select {
case result := <-ch:
fmt.Println("Got result:", result)
case <-time.After(2 * time.Second):
fmt.Println("Timeout!")
}Das verhindert, dass dein Programm für immer wartet, wenn eine Kanaloperation möglicherweise nie abgeschlossen wird.
Aufgabe
EinfachLass uns einen Dienstmonitor erstellen, der die Anweisung select verwendet, um mehrere gleichzeitig laufende Datenquellen zu verarbeiten. Dein Monitor wird gleichzeitig verschiedene Dienstkanäle überwachen und angemessen reagieren, wenn Daten eintreffen oder keine Aktualisierungen verfügbar sind.
Du wirst deinen Code auf zwei Dateien aufteilen:
monitor.go: Definiere hier deine Überwachungslogik für Dienste mit einer auf select basierenden Kanalverarbeitung.Erstelle eine
ServiceUpdate-Struktur mit den FeldernName(string) undStatus(string).Implementiere eine
Monitor-Funktion, die drei Kanäle entgegennimmt:primary chan ServiceUpdate,backup chan ServiceUpdateunddone chan bool. Diese Funktion sollselectverwenden, um gleichzeitig auf allen drei Kanälen zu lauschen:- Beim Empfangen von
primary: Gib die formatierte ZeichenkettePrimary: [Name] is [Status]zurück - Beim Empfangen von
backup: Gib die formatierte ZeichenketteBackup: [Name] is [Status]zurück - Beim Empfangen von
done: GibMonitoring stoppedzurück
Implementiere eine
CheckStatus-Funktion, die einen einzelnenupdates chan ServiceUpdate-Kanal entgegennimmt undselectmit einemdefault-Fall für eine nicht blockierende Prüfung verwendet:- Wenn eine Aktualisierung verfügbar ist: Gib
Update available: [Name]zurück - Wenn keine Aktualisierung verfügbar ist (Standardfall): Gib
No updates pendingzurück
- Beim Empfangen von
main.go: Richte die Kanäle ein und demonstriere sowohl blockierendes als auch nicht blockierendes select-Verhalten.Lies einen Modus aus der Eingabe, der bestimmt, welches Szenario ausgeführt wird:
primary,backup,stopodercheck.Für die Modi
primary,backupundstop: Lies außerdem einen Dienstnamen und einen Status ein. Erstelle die drei Kanäle, starte eine Goroutine, die abhängig vom Modus Daten an den entsprechenden Kanal sendet, rufe anschließendMonitorauf und gib dessen Ergebnis aus.Für den Modus
check: Lies einen Dienstnamen und einen Status sowie ein Kennzeichen (sendodernosend) ein, das angibt, ob vor der Prüfung Daten gesendet werden sollen. Erstelle einen gepufferten Kanal mit der Kapazität 1. Wenn das Kennzeichensendlautet, sende eine Aktualisierung an den Kanal, bevor duCheckStatusaufrufst. Gib das Ergebnis vonCheckStatusaus.
Die folgenden Eingaben werden bereitgestellt:
- Zeile 1: Modus (
primary,backup,stopodercheck) - Zeile 2: Dienstname
- Zeile 3: Dienststatus
- Zeile 4 (nur für den Modus
check):sendodernosend
Beispiel für folgende Eingabe:
primary
Database
healthyDeine Ausgabe sollte wie folgt aussehen:
Primary: Database is healthyUnd bei folgender Eingabe:
check
Cache
active
nosendDeine Ausgabe sollte wie folgt aussehen:
No updates pendingProbier es selbst
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: Behandle verschiedene Modi: "primary", "backup", "stop", "check"
// Für Modi "primary", "backup", "stop":
// - Erstelle drei Channels: primary, backup, done
// - Starte eine Goroutine, die Daten an den entsprechenden Channel sendet
// - Rufe Monitor auf und gib das Ergebnis aus
// Für Modus "check":
// - Lies das zusätzliche Flag ("send" oder "nosend")
// - Erstelle einen gepufferten Channel mit Kapazität 1
// - Wenn das Flag "send" ist, sende ein Update an den Channel
// - Rufe CheckStatus auf und gib das Ergebnis aus
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP in Go
Externe DateienGo-Workspace & ModulePackages & ImportsExportierte vs. nicht exportierte NamenEinführung in OOP mit GoStructs als KlassenMethoden für Structs definierenPointer- vs. Value-ReceiverStruct-InitialisierungKonstruktorfunktionenRückblick – Einfacher Taschenrechner4Schnittstellen
Einführung in SchnittstellenImplizite ImplementierungSchnittstelle als VertragLeere Schnittstelle (any)TypzusicherungTypwechselZusammensetzung von SchnittstellenStringer- und Error-SchnittstellenRückblick – Formenrechner7Kapselung
Exportierte vs. nicht exportierte FelderKapselung auf PaketebeneGetter- und Setter-MethodenInformationsverbergung in GoRückblick – Studierendendatensätze10Generics (Go 1.18+)
Einführung in GenericsTypparameterTypbeschränkungenGenerische StrukturenWorkaround für generische MethodenZusammenfassung – Generische Sammlung2Typen & Structs im Detail
Grundlegende & zusammengesetzte TypenBenutzerdefinierte TypdefinitionenStruct-TagsAnonyme StructsVerschachtelte StructsNullwerte & StandardwerteRückblick – Kontaktbuch5Komposition statt Vererbung
Warum Go keine Vererbung hatGrundlagen der Struct-EinbettungMethoden-PromotionMehrere Structs einbettenEinbettung vs. AggregationVerbergen eingebetteter MethodenRückblick – Mitarbeiterhierarchie8Fehlerbehandlung & OOP
Das Error-InterfaceBenutzerdefinierte FehlertypenError-Wrapping (fmt.Errorf)Sentinel-Fehlererrors.Is() und errors.As()Panic, Defer und RecoverRückblick – Dateiparser3Zeiger & Speicher
Grundlagen von Zeigern in GoZeiger auf StructsÜbergabe per Wert vs. ReferenzDie Funktion new()Garbage Collection in GoRückblick – Verkettete Liste erstellen6Polymorphismus in Go
Polymorphismus über InterfacesDuck-Typing in GoRegeln zur Interface-ErfüllungPolymorphe SammlungenDependency InjectionZusammenfassung – Zahlungsprozessor9Konkurrenz & OOP
Grundlagen der GoroutinesChannels & KommunikationGepufferte vs. ungepufferte ChannelsSelect-Anweisungsync.Mutex & sync.RWMutexsync.WaitGroupThread-sicheres Struct-DesignRückblick – Worker PoolÜbe selbstständig: Online-Go-Compiler