0Pricing
Go Academy · Lektion

Gepufferte Channels

Kapazität, Channels schließen und einen Channel mit range durchlaufen

Gepufferte Channels ist eine kostenlose Go Academy-Lektion auf CoddyKit. Dies ist Lektion 3 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Go Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Go Academy-Kurs umfasst insgesamt 4 Lektionen.

Was ist ein gepufferter Channel?

Ein gepufferter Channel hat eine Kapazität — Sendevorgänge blockieren nicht, solange im Puffer Platz ist. Der Channel fungiert als Warteschlange:

package main
import "fmt"

func main() {
    ch := make(chan int, 3)  // capacity 3

    ch <- 1  // does not block — buffer has room
    ch <- 2  // does not block
    ch <- 3  // does not block
    // ch <- 4  // would block — buffer full

    fmt.Println(<-ch) // 1
    fmt.Println(<-ch) // 2
    fmt.Println(<-ch) // 3
}

Gepufferter Channel als Warteschlange

Gepufferte Channels implementieren eine FIFO-Warteschlange zwischen Goroutines:

package main
import ("fmt"; "sync")

func producer(ch chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 1; i <= 5; i++ {
        ch <- i
        fmt.Printf("produced %d\n", i)
    }
}

func main() {
    ch := make(chan int, 2)  // buffer 2 — producer runs ahead
    var wg sync.WaitGroup
    wg.Add(1)
    go producer(ch, &wg)
    wg.Wait()
    close(ch)
    for v := range ch { fmt.Printf("consumed %d\n", v) }
}

len() und cap() bei Channels

Ermitteln Sie die aktuelle Größe und Kapazität eines gepufferten Channels:

package main
import "fmt"

func main() {
    ch := make(chan string, 5)
    ch <- "a"
    ch <- "b"
    ch <- "c"

    fmt.Println("cap:", cap(ch))  // 5
    fmt.Println("len:", len(ch))  // 3 — items currently buffered

    <-ch
    fmt.Println("len:", len(ch))  // 2
}

Produzent und Konsument entkoppeln

Ein Puffer entkoppelt die Geschwindigkeit des Produzenten von der des Konsumenten. Der Produzent kann um die Puffergröße vorlaufen, bevor er blockiert:

package main
import ("fmt"; "sync"; "time")

func produce(ch chan<- int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        ch <- i
    }
}

func consume(ch <-chan int, wg *sync.WaitGroup) {
    defer wg.Done()
    for v := range ch {
        time.Sleep(10 * time.Millisecond)  // slower consumer
        fmt.Println("consumed:", v)
    }
}

func main() {
    ch := make(chan int, 3)
    var wg sync.WaitGroup
    wg.Add(2)
    go produce(ch, &wg)
    go consume(ch, &wg) // BUG: produce closes before consume sees all
    // In practice, coordinate close carefully
    fmt.Println("decoupled")
}

Semaphore mit gepuffertem Channel

Ein gepufferter Channel mit der Kapazität N kann die Anzahl gleichzeitig ausgeführter Goroutines auf N begrenzen — eine einfache Semaphore:

package main
import ("fmt"; "sync"; "time")

func main() {
    sem := make(chan struct{}, 3)  // max 3 concurrent
    var wg sync.WaitGroup

    for i := 0; i < 10; i++ {
        wg.Add(1)
        i := i
        go func() {
            defer wg.Done()
            sem <- struct{}{}    // acquire
            defer func() { <-sem }()  // release
            fmt.Printf("job %d running\n", i)
            time.Sleep(50 * time.Millisecond)
        }()
    }
    wg.Wait()
}

Einen gepufferten Channel schließen

Durch das Schließen eines gepufferten Channels können Empfänger die noch gepufferten Werte auslesen, bevor sie das Schließen erkennen:

package main
import "fmt"

func main() {
    ch := make(chan int, 5)
    for i := 1; i <= 3; i++ { ch <- i }
    close(ch)

    // Drain all buffered values after close:
    for v := range ch {
        fmt.Println(v)  // 1, 2, 3
    }
    // range exits after channel closed and drained
}

Gepuffert vs. ungepuffert: Wann welche Variante?

Entscheidungshilfe:

  • Ungepuffert: garantierte synchrone Übergabe, strikte Reihenfolge, Rendezvous-Synchronisierung
  • Gepuffert: Geschwindigkeiten von Produzent und Konsument entkoppeln, Blockierungen reduzieren, Semaphoren implementieren, N Ergebnisse sammeln
  • Verwenden Sie standardmäßig ungepufferte Channels — fügen Sie nur dann einen Puffer hinzu, wenn Sie dessen Größe begründen können
  • Ein zu kleiner Puffer → blockiert weiterhin; ein zu großer Puffer → verbirgt Fehler

Ergebnisse mit einem gepufferten Channel sammeln

Verwenden Sie einen gepufferten Channel, um Ergebnisse paralleler Goroutines zu sammeln, ohne zu blockieren:

package main
import ("fmt"; "sync")

func square(n int) int { return n * n }

func main() {
    nums := []int{1, 2, 3, 4, 5}
    results := make(chan int, len(nums))  // buffer = goroutine count
    var wg sync.WaitGroup

    for _, n := range nums {
        wg.Add(1)
        n := n
        go func() {
            defer wg.Done()
            results <- square(n)
        }()
    }
    wg.Wait()
    close(results)

    for r := range results { fmt.Println(r) }
}

Goroutine-Leak bei vollem Puffer

Wenn der Puffer voll ist und kein Leser existiert, blockiert der Sender für immer — ein Goroutine-Leak:

package main
import ("fmt"; "time"; "runtime")

func main() {
    ch := make(chan int, 2)
    // Start goroutine that fills buffer and then blocks
    go func() {
        ch <- 1
        ch <- 2
        ch <- 3  // blocks: buffer full, no receiver
        fmt.Println("never reached")
    }()
    time.Sleep(50 * time.Millisecond)
    fmt.Println("goroutines:", runtime.NumGoroutine()) // 2 — leaked
}

time.After als gepufferter Channel

time.After gibt einen mit 1 gepufferten <-chan time.Time zurück. Die Laufzeitumgebung sendet nach Ablauf der Dauer einen Wert an ihn; anschließend wird er durch die Garbage Collection entfernt:

package main
import ("fmt"; "time")

func doWithTimeout(work func() string) (string, bool) {
    result := make(chan string, 1)
    go func() { result <- work() }()
    select {
    case r := <-result:
        return r, true
    case <-time.After(100 * time.Millisecond):
        return "", false
    }
}

func main() {
    r, ok := doWithTimeout(func() string {
        time.Sleep(50 * time.Millisecond)
        return "done"
    })
    fmt.Println(r, ok)
}

Kurztest

Was geschieht, wenn Sie an einen gepufferten Channel senden, dessen Kapazität bereits voll ausgeschöpft ist?

Zusammenfassung: Gepufferte Channels

Zusammenfassung:

  • make(chan T, N) erstellt einen gepufferten Channel mit der Kapazität N
  • Sendevorgänge blockieren nur, wenn der Puffer voll ist; Empfang blockiert nur, wenn er leer ist
  • len(ch) — aktuelle Anzahl der Elemente; cap(ch) — Kapazität
  • Verwenden Sie sie, um Produzenten und Konsumenten zu entkoppeln, parallele Ergebnisse zu sammeln und Semaphoren zu implementieren
  • Das Schließen ermöglicht das Leeren vor EOF; range ch erledigt dies automatisch

Häufig gestellte Fragen

Ist die Lektion „Gepufferte Channels“ kostenlos?

Ja — der vollständige Text von „Gepufferte Channels“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Go Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Go Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Gepufferte Channels“?

Kapazität, Channels schließen und einen Channel mit range durchlaufen Du übst Go Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Go Academy zu starten?

Keine Vorkenntnisse erforderlich. Go Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 3 von 4.

Wie lange dauert die Lektion „Gepufferte Channels“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Go Academy-Lektion Code schreiben und ausführen?

Ja. Jede Go Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Goroutines starten
  2. Ungepufferte Channels
  3. Gepufferte Channels
  4. Channel-Richtung und Pipeline-Patterns
← Zurück zu Go Academy