Menu
Coddy logo textTech

Select-Anweisung

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 62 von 107.

Die select-Anweisung lässt eine Goroutine gleichzeitig auf mehrere Channel-Operationen warten. Sie ist wie eine switch-Anweisung, aber jeder Case beinhaltet ein Senden oder Empfangen über einen Channel. Wenn mehrere Channel bereit sind, wählt select einen 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 das Empfangen von ch1 blockieren, bis Daten ankommen, wodurch potenziell Daten auf ch2 verpasst werden. Mit select wird der Kanal zuerst verarbeitet, der zuerst Daten empfängt.

Der default-Fall 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 gängiges Muster kombiniert select mit Timeouts unter Verwendung von time.After, das einen Channel 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!")
}

Dies verhindert, dass Ihr Programm unendlich lange wartet, wenn eine Channel-Operation möglicherweise nie abgeschlossen wird.

challenge icon

Aufgabe

Einfach

Lassen Sie uns einen Service-Monitor bauen, der die select-Anweisung verwendet, um mehrere gleichzeitige Datenquellen zu verarbeiten. Ihr Monitor wird gleichzeitig auf verschiedene Service-Kanäle hören und angemessen reagieren, wenn Daten ankommen oder wenn keine Updates verfügbar sind.

Sie werden Ihren Code auf zwei Dateien verteilen:

  • monitor.go: Definieren Sie Ihre Service-Monitoring-Logik mit select-basierter Kanalverarbeitung.

    Erstellen Sie ein ServiceUpdate-Struct mit den Feldern Name (string) und Status (string).

    Implementieren Sie eine Monitor-Funktion, die drei Kanäle entgegennimmt: primary chan ServiceUpdate, backup chan ServiceUpdate und done chan bool. Diese Funktion sollte select verwenden, um gleichzeitig auf allen drei Kanälen zu hören:

    • Beim Empfang von primary: Geben Sie den formatierten String Primary: [Name] is [Status] zurück.
    • Beim Empfang von backup: Geben Sie den formatierten String Backup: [Name] is [Status] zurück.
    • Beim Empfang von done: Geben Sie Monitoring stopped zurück.

    Implementieren Sie eine CheckStatus-Funktion, die einen einzelnen updates chan ServiceUpdate entgegennimmt und select mit einem default-Fall verwendet, um eine nicht-blockierende Prüfung durchzuführen:

    • Wenn ein Update verfügbar ist: Geben Sie Update available: [Name] zurück.
    • Wenn kein Update verfügbar ist (default-Fall): Geben Sie No updates pending zurück.
  • main.go: Richten Sie die Kanäle ein und demonstrieren Sie sowohl blockierendes als auch nicht-blockierendes select-Verhalten.

    Lesen Sie einen Modus aus der Eingabe, der bestimmt, welches Szenario ausgeführt werden soll: primary, backup, stop oder check.

    Für die Modi primary, backup und stop: Lesen Sie zusätzlich einen Service-Namen und einen Status ein. Erstellen Sie die drei Kanäle, starten Sie eine Goroutine, die basierend auf dem Modus Daten an den entsprechenden Kanal sendet, rufen Sie dann Monitor auf und geben Sie das Ergebnis aus.

    Für den Modus check: Lesen Sie einen Service-Namen und einen Status ein, plus ein Flag (send oder nosend), das angibt, ob vor der Prüfung Daten gesendet werden sollen. Erstellen Sie einen gepufferten Kanal mit der Kapazität 1. Wenn das Flag send ist, senden Sie ein Update an den Kanal, bevor Sie CheckStatus aufrufen. Geben Sie das Ergebnis von CheckStatus aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Modus (primary, backup, stop oder check)
  • Zeile 2: Service-Name
  • Zeile 3: Service-Status
  • Zeile 4 (nur für den Modus check): send oder nosend

Zum Beispiel, gegeben:

primary
Database
healthy

Sollte Ihre Ausgabe wie folgt aussehen:

Primary: Database is healthy

Und gegeben:

check
Cache
active
nosend

Sollte Ihre Ausgabe wie folgt aussehen:

No updates pending

Spickzettel

Die select-Anweisung ermöglicht es einer Goroutine, gleichzeitig auf mehrere Channel-Operationen zu warten. Sie funktioniert wie eine switch-Anweisung, aber jeder Case beinhaltet das Senden oder Empfangen über einen Channel:

select {
case msg1 := <-ch1:
    fmt.Println(msg1)
case msg2 := <-ch2:
    fmt.Println(msg2)
}

Wenn mehrere Channels bereit sind, wählt select einen zufällig aus. Ohne select würde das Empfangen von einem Channel blockieren und potenziell Daten auf einem anderen Channel verpassen.

Der default-Case macht select nicht-blockierend – er wird sofort ausgeführt, wenn keine Channels bereit sind:

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

Ein gängiges Muster kombiniert select mit Timeouts unter Verwendung von time.After, was einen Channel 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!")
}

Dies verhindert, dass Ihr Programm ewig wartet, wenn eine Channel-Operation möglicherweise nie abgeschlossen wird.

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: Verschiedene Modi verarbeiten: "primary", "backup", "stop", "check"
	
	// Für die Modi "primary", "backup", "stop":
	// - Drei Kanäle erstellen: primary, backup, done
	// - Eine Goroutine starten, die Daten an den entsprechenden Kanal sendet
	// - Monitor aufrufen und das Ergebnis ausgeben
	
	// Für den Modus "check":
	// - Das zusätzliche Flag lesen ("send" oder "nosend")
	// - Einen gepufferten Kanal mit Kapazität 1 erstellen
	// - Wenn das Flag "send" ist, ein Update an den Kanal senden
	// - CheckStatus aufrufen und das Ergebnis ausgeben
	
}
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