Channel-Richtung und Pipeline-Patterns
Nur-Lese-, Nur-Schreib-Channels und Pipelines
Channel-Richtung und Pipeline-Patterns ist eine kostenlose Go Academy-Lektion auf CoddyKit. Dies ist Lektion 4 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.
Gerichtete Channel-Typen
Go ermöglicht es, Channels in Typsignaturen auf das Senden oder den Empfang zu beschränken. Dadurch wird die Absicht dokumentiert und eine falsche Verwendung verhindert:
package main
// send-only: can only send, not receive or close (close is allowed by sender)
func sender(out chan<- int) {
out <- 42
}
// receive-only: can only receive, not send or close
func receiver(in <-chan int) int {
return <-in
}
// bidirectional: can do both
func relay(in <-chan int, out chan<- int) {
out <- <-in
}Channel-Richtungen konvertieren
Ein bidirektionaler Channel kann implizit in jeden der beiden gerichteten Typen konvertiert werden, aber nicht umgekehrt:
package main
import "fmt"
func produce(out chan<- int) { out <- 1; close(out) }
func consume(in <-chan int) { fmt.Println(<-in) }
func main() {
ch := make(chan int) // bidirectional
go produce(ch) // auto-converts to chan<- int
consume(ch) // auto-converts to <-chan int
// chan<- int cannot be converted back to <-chan int
}Pipeline: Stufe 1 — Generator
Eine Pipeline verknüpft Goroutines, wobei jede Stufe aus dem Ausgabekanal der vorherigen Stufe liest. Der Generator ist die erste Stufe:
package main
import "fmt"
func generate(nums ...int) <-chan int {
out := make(chan int)
go func() {
for _, n := range nums {
out <- n
}
close(out)
}()
return out
}
func main() {
ch := generate(2, 3, 4, 5)
for v := range ch { fmt.Println(v) }
}Pipeline: Stufe 2 — Transformation
Mittlere Stufen empfangen Daten von einem Channel, transformieren sie und senden sie an einen anderen:
package main
import "fmt"
func generate(nums ...int) <-chan int {
out := make(chan int)
go func() { for _, n := range nums { out <- n }; close(out) }()
return out
}
func square(in <-chan int) <-chan int {
out := make(chan int)
go func() {
for v := range in { out <- v * v }
close(out)
}()
return out
}
func main() {
for v := range square(generate(2, 3, 4, 5)) {
fmt.Println(v) // 4, 9, 16, 25
}
}Pipeline: Vollständiges Beispiel mit drei Stufen
Drei Stufen verknüpfen — erzeugen, transformieren, filtern:
package main
import "fmt"
func gen(nums ...int) <-chan int {
c := make(chan int)
go func() { for _, n := range nums { c <- n }; close(c) }()
return c
}
func double(in <-chan int) <-chan int {
c := make(chan int)
go func() { for v := range in { c <- v * 2 }; close(c) }()
return c
}
func evens(in <-chan int) <-chan int {
c := make(chan int)
go func() { for v := range in { if v%2 == 0 { c <- v } }; close(c) }()
return c
}
func main() {
for v := range evens(double(gen(1,2,3,4,5))) {
fmt.Println(v) // 2, 4, 6, 8, 10
}
}Pipeline-Abbruch mit dem done-Channel
Übergeben Sie einen done-Channel, damit Pipeline-Stufen bei einem Abbruch vorzeitig beendet werden können:
package main
import "fmt"
func gen(done <-chan struct{}, nums ...int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for _, n := range nums {
select {
case out <- n:
case <-done: // cancel signal
return
}
}
}()
return out
}
func main() {
done := make(chan struct{})
ch := gen(done, 1, 2, 3, 4, 5)
fmt.Println(<-ch) // 1
close(done) // cancel remaining work
fmt.Println("pipeline cancelled")
}Fan-out: Arbeit verteilen
Fan-out verteilt die Arbeit aus einem Channel auf mehrere Goroutines zur parallelen Verarbeitung:
package main
import ("fmt"; "sync")
func fanOut(in <-chan int, workers int) []<-chan int {
outs := make([]<-chan int, workers)
for i := 0; i < workers; i++ {
out := make(chan int)
outs[i] = out
go func() {
for v := range in { out <- v * v } // each worker processes
close(out)
}()
}
return outs
}
func main() {
fmt.Println("fan-out distributes work to multiple goroutines")
_ = sync.WaitGroup{}
}Fan-in: Channels zusammenführen
Fan-in führt mehrere Kanäle zusammen:
package main
import ("fmt"; "sync")
func merge(cs ...<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
for _, c := range cs {
wg.Add(1)
c := c
go func() { defer wg.Done(); for v := range c { out <- v } }()
}
go func() { wg.Wait(); close(out) }()
return out
}
func gen(nums ...int) <-chan int {
c := make(chan int)
go func() { for _, n := range nums { c <- n }; close(c) }()
return c
}
func main() {
for v := range merge(gen(1,2), gen(3,4), gen(5,6)) {
fmt.Println(v)
}
}Best Practices für Pipelines
Grundsätze für das Pipeline-Design:
- Jede Stufe: Eine Goroutine liest aus
<-chan, schreibt inchan<-und schließt die Ausgabe, sobald sie fertig ist - Nur der Produzent schließt den Kanal – niemals der Konsument
- Übergeben Sie zur Abbruchsteuerung einen
done-Kanal (oder einen Kontext) - Verwenden Sie gerichtete Kanaltypen in allen Funktionssignaturen
- Leeren Sie Kanäle bei einem Abbruch, um Goroutine-Leaks zu verhindern
Pipeline aus der Praxis: CSV-Verarbeitung
Pipelines sind besonders für die Datenverarbeitung geeignet – Zeilen lesen, analysieren, filtern und umwandeln:
package main
import ("fmt"; "strings")
func splitLines(data string) <-chan string {
out := make(chan string)
go func() {
for _, line := range strings.Split(data, "\n") {
if line != "" { out <- line }
}
close(out)
}()
return out
}
func main() {
csv := "alice,30\nbob,25\ncarol,35"
for line := range splitLines(csv) {
parts := strings.Split(line, ",")
fmt.Printf("name=%s age=%s\n", parts[0], parts[1])
}
}Kurze Überprüfung
Welchen Zweck haben gerichtete Kanaltypen in Funktionssignaturen?
Zusammenfassung: Kanalrichtung und Pipelines
Zusammenfassung:
chan<- Tnur zum Senden,<-chan Tnur zum Empfangen – dokumentierte Absicht und Sicherheit zur Compilezeit- Pipelines: Verketten Sie Goroutinen, wobei jede aus einem Kanal liest und in einen anderen schreibt
- Fan-out: Ein Eingangskanal → mehrere Goroutinen
- Fan-in: Mehrere Kanäle → Zusammenführung in einen Kanal
- Schließen Sie Kanäle immer senderseitig; verwenden Sie zur Abbruchsteuerung einen done-Kanal
Häufig gestellte Fragen
Ist die Lektion „Channel-Richtung und Pipeline-Patterns“ kostenlos?
Ja — der vollständige Text von „Channel-Richtung und Pipeline-Patterns“ 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 „Channel-Richtung und Pipeline-Patterns“?
Nur-Lese-, Nur-Schreib-Channels und Pipelines 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 4 von 4.
Wie lange dauert die Lektion „Channel-Richtung und Pipeline-Patterns“?
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
- Goroutines starten
- Ungepufferte Channels
- Gepufferte Channels
- Channel-Richtung und Pipeline-Patterns