Direkt zum Hauptinhalt springen
eLearner.app
Modul 7 · Lektion 3 von 533/50 im Kurs~12 min
Lektionen des Moduls (3/5)

`select`: Multiplexing von Kanälen

select wartet auf mehrere Kanaloperationen gleichzeitig. Es ist der switch der Go-Parallelität: Er ermöglicht es Ihnen, auf den ersten zu reagieren Kanal bereit unter vielen.

Syntax

Go
select {
case v := <-ch1:
    fmt.Println("ch1:", v)
case v := <-ch2:
    fmt.Println("ch2:", v)
case ch3 <- 99:
    fmt.Println("inviato su ch3")
case <-time.After(time.Second):
    fmt.Println("timeout")
default:
    fmt.Println("nessuno è pronto")
}

Semantik:

  • Alle Fälle werden ausgewertet; Nur einer der fertigen Fälle wird ausgewählt.
  • Wenn mehrere Fälle bereit sind, erfolgt die Auswahl pseudozufällig (keine Reihenfolge).
  • Wenn kein Fall bereit ist: Der select blockiert, bis einer bereit wird.
  • Wenn ein default vorhanden ist: Dieser wird sofort ausgeführt, wenn kein Fall bereit ist (nicht blockierende Auswahl).

Timeout-Muster

Go
select {
case res := <-fetch(url):
    use(res)
case <-time.After(2 * time.Second):
    log.Println("timeout: fetch troppo lento")
}

time.After(d) gibt einen <-chan Time zurück, der einen Wert nach d erzeugt. Es ist die klassische Art, die Wartezeit zu verkürzen.

Nicht blockierende Auswahl mit Standardeinstellung

Go
select {
case msg := <-ch:
    process(msg)
default:
    // niente da fare, prosegui
}

Es „fragt“ den Kanal ab, ohne ihn zu blockieren. Nützlich in Codepfaden, die muss reaktionsfähig bleiben, ohne zwingend warten zu müssen.

Muster „Fertig-Kanal“.

Kombinieren Sie select mit einem Stornierungskanal:

Go
func worker(in <-chan Job, done <-chan struct{}) {
    for {
        select {
        case j := <-in:
            process(j)
        case <-done:
            return       // chi gestisce done segnala lo shutdown
        }
    }
}

close(done) vom Koordinator löst jeweils case <-done aus Wartende Goroutine: Koordiniertes Herunterfahren.

Schleife mit Auswahl

Go
for {
    select {
    case v := <-input:
        if v == nil {
            return
        }
        handle(v)
    case <-time.After(5 * time.Second):
        keepAlive()
    case <-ctx.Done():
        return
    }
}

Das typische „Ereignisschleifen“-Muster für Server und Worker.

Ein Null-Kanal als „deaktivierter“ Fall

Ein fortgeschrittener Trick: Ein case <-ch mit ch == nil ist nie ausgewählt. Damit können Sie einen Fall dynamisch „deaktivieren“:

Go
var in chan int = source()
for {
    select {
    case v, ok := <-in:
        if !ok {
            in = nil    // disabilita questo case
            continue
        }
        handle(v)
    case <-ctx.Done():
        return
    }
}

Wenn in geschlossen ist, setze ich es auf Null: select verarbeitet weiterhin nur das andere Fälle.

Probieren Sie es aus

Übung#go.m7.l3.e1
Versuche: 0Wird geladen…

Implementieren Sie eine Auswahl mit zwei Fällen, die von CH1 und CH2 empfangen. Drucken Sie aus, welches zuerst angekommen ist.

Editor wird geladen…
Hinweis anzeigen

Syntax `select { case ...: ... }` mit einem Fall pro Kanal.

Lösung nach 3 Versuchen verfügbar

Übung#go.m7.l3.e2
Versuche: 0Wird geladen…

Fügen Sie der Auswahl mithilfe von time.After(time.Second) einen Timeout-Fall hinzu.

Editor wird geladen…
Hinweis anzeigen

`time.After(d)` ist ein Kanal, der nach d empfängt.

Lösung nach 3 Versuchen verfügbar

Quiz#go.m7.l3.e3
Bereit

Was macht eine Auswahl nicht blockierend?

Go
select { case v := <-ch: ... ??? }
Antwortoptionen

Zusammenfassung

select wartet auf den ersten Bereitschaftsfall unter mehreren Kanaloperationen.

  • Pseudozufällige Auswahl aus mehreren fertigen Fällen.
  • default → nicht blockierende Auswahl (Polling).
  • time.After(d) für Zeitüberschreitungen (beachten Sie das Leck in Schleifen: verwenden Sie context).
  • Muster: Fertig-Kanal, Ereignisschleife, Null-Kanal zum Deaktivieren eines Falls.
  • Leerer select{} = ewiger Block: fast immer ein Fehler.