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 cherledigt 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.