Menu
Coddy logo textTech

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.

challenge icon

Aufgabe

Einfach

Lass 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 Feldern Name (string) und Status (string).

    Implementiere eine Monitor-Funktion, die drei Kanäle entgegennimmt: primary chan ServiceUpdate, backup chan ServiceUpdate und done chan bool. Diese Funktion soll select verwenden, um gleichzeitig auf allen drei Kanälen zu lauschen:

    • Beim Empfangen von primary: Gib die formatierte Zeichenkette Primary: [Name] is [Status] zurück
    • Beim Empfangen von backup: Gib die formatierte Zeichenkette Backup: [Name] is [Status] zurück
    • Beim Empfangen von done: Gib Monitoring stopped zurück

    Implementiere eine CheckStatus-Funktion, die einen einzelnen updates chan ServiceUpdate-Kanal entgegennimmt und select mit einem default-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 pending zurück
  • 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, stop oder check.

    Für die Modi primary, backup und stop: 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ßend Monitor auf und gib dessen Ergebnis aus.

    Für den Modus check: Lies einen Dienstnamen und einen Status sowie ein Kennzeichen (send oder nosend) ein, das angibt, ob vor der Prüfung Daten gesendet werden sollen. Erstelle einen gepufferten Kanal mit der Kapazität 1. Wenn das Kennzeichen send lautet, sende eine Aktualisierung an den Kanal, bevor du CheckStatus aufrufst. Gib das Ergebnis von CheckStatus aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Modus (primary, backup, stop oder check)
  • Zeile 2: Dienstname
  • Zeile 3: Dienststatus
  • Zeile 4 (nur für den Modus check): send oder nosend

Beispiel für folgende Eingabe:

primary
Database
healthy

Deine Ausgabe sollte wie folgt aussehen:

Primary: Database is healthy

Und bei folgender Eingabe:

check
Cache
active
nosend

Deine Ausgabe sollte wie folgt aussehen:

No updates pending

Probier 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
	
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Online-Go-Compiler