⥠1. Channel-Multiplexing mit select
Das select-Statement Ă€hnelt einem switch, jedoch fĂŒr Channel-Operationen: Es wartet darauf, dass mindestens ein Case kommunikationsbereit ist (Senden oder Empfangen). Sind mehrere Cases gleichzeitig bereit, wĂ€hlt Go pseudo-zufĂ€llig einen aus (Fairness-Garantie).
[select] ââââââŒâââ [Kanal B: Backup DB] ââââŒâââ> Wer zuerst Daten hat, gewinnt!
ââââ [time.After(100ms): Timeout] â
select {
case msg1 := <-ch1:
fmt.Println("Empfangen von ch1:", msg1)
case msg2 := <-ch2:
fmt.Println("Empfangen von ch2:", msg2)
case <-time.After(500 * time.Millisecond):
fmt.Println("â ïž Timeout! Beide KanĂ€le antworten zu langsam.")
default:
// Wird SOFORT ausgefĂŒhrt, wenn kein Kanal bereit ist (Nicht-blockierend!)
fmt.Println("Keine Daten vorhanden.")
}
đĄïž 2. Robuste Cancellation mit context.Context
In Cloud-Microservices muss jeder Request bei Client-AbbrĂŒchen oder Timeouts sofort kaskadierend gestoppt werden. Das context-Paket ist in Go der offizielle Standard fĂŒr Deadlines und Abbruchsignale:
import (
"context"
"time"
)
func QueryDatabase(ctx context.Context) (string, error) {
// Erstelle einen Channel fĂŒr das Abfrageergebnis
resultCh := make(chan string, 1)
go func() {
// Simuliere langwierige DB-Abfrage
time.Sleep(200 * time.Millisecond)
resultCh <- "Kundendaten #42"
}()
select {
case <-ctx.Done():
// Wurde abgebrochen (Timeout oder Cancel)
return "", ctx.Err() // z.B. context.DeadlineExceeded
case res := <-resultCh:
return res, nil
}
}
func main() {
// đŻ Timeout von 100ms definieren:
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel() // Ressourcen immer freigeben!
res, err := QueryDatabase(ctx)
if err != nil {
fmt.Println("Fehler:", err) // Ausgabe: context deadline exceeded
}
}
Stell dir einen Hotel-Concierge vor:
Er hat ein rotes Telefon (ch1) fĂŒr den Zimmerservice und ein blaues Telefon (ch2) fĂŒr Taxibestellungen. Mit select nimmt er sofort den Hörer ab, der zuerst klingelt. Hat er eine Sanduhr aufgestellt (time.After) und nach 5 Minuten klingelt keines der Telefone, schlieĂt er den Schalter (Timeout). context.Context ist der GeneralschlĂŒssel, mit dem die GeschĂ€ftsleitung alle laufenden AuftrĂ€ge auf einen Schlag abbricht.
đ 3. Cheat-Sheet: select & Context Patterns
| Muster | Code-Beispiel | Zweck |
|---|---|---|
| Non-Blocking Read | select { case v := <-ch: ... default: ... } |
Liest sofort ohne Blockieren des aktuellen Threads |
| Non-Blocking Write | select { case ch <- v: ... default: ... } |
Verwirft oder puffert Daten wenn Channel voll ist |
| Hard Timeout | case <-time.After(2 * time.Second): |
Bricht Warten nach Zeitintervall zuverlÀssig ab |
| Context Done | case <-ctx.Done(): return ctx.Err() |
Kaskadierende Stornierung durch Microservice-Chain |
đ§ Diagnostischer Selbst-Check
ĂberprĂŒfe dein VerstĂ€ndnis der Kernkonzepte und typischen Go-Fallen, bevor du die Ăbung in der Web-IDE bearbeitest.
đŻ Aufgaben & Checkliste in aufgabe.go
In Go ist es die feste Konvention, ctx context.Context immer als ersten Parameter an I/O- oder Netzwerkfunktionen zu ĂŒbergeben (z.B. func FetchUser(ctx context.Context, id int)).