Menu
Coddy logo textTech

Channels & Kommunikation

Teil des Abschnitts Objektorientierte Programmierung der GO-Journey von Coddy — Lektion 60 von 107.

Channels sind Gos primärer Mechanismus für die Kommunikation zwischen Goroutinen. Anstatt Speicher direkt zu teilen, senden und empfangen Goroutinen Werte über Channels, gemäß der Philosophie von Go: „Kommuniziere nicht durch das Teilen von Speicher; teile Speicher durch Kommunizieren.“

Erstellen Sie einen Channel mit der make-Funktion und dem chan-Schlüsselwort:

messages := make(chan string)

Verwenden Sie den Pfeil-Operator <-, um Werte zu senden und zu empfangen. Der Pfeil zeigt in die Richtung des Datenflusses:

func main() {
    messages := make(chan string)
    
    go func() {
        messages <- "hello"  // an den Channel senden
    }()
    
    msg := <-messages  // vom Channel empfangen
    fmt.Println(msg)   // Ausgabe: hello
}

Standardmäßig blockieren Sendevorgänge und Empfangsvorgänge, bis die andere Seite bereit ist. Wenn die Goroutine "hello" sendet, wartet sie, bis main bereit zum Empfangen ist. Dieses blockierende Verhalten bietet eine integrierte Synchronisation – kein time.Sleep erforderlich.

Sie können einen Channel schließen, um zu signalisieren, dass keine weiteren Werte gesendet werden. Empfänger können dies erkennen:

close(messages)

msg, ok := <-messages
if !ok {
    fmt.Println("Channel closed")
}

Channels sind typisiert – ein chan string kann nur Strings übertragen. Diese Typsicherheit stellt sicher, dass Goroutinen mit den korrekten Datentypen kommunizieren, wodurch Fehler bereits zur Kompilierzeit statt zur Laufzeit abgefangen werden.

challenge icon

Aufgabe

Einfach

Lassen Sie uns ein Nachrichten-Relay-System bauen, das demonstriert, wie Goroutinen über Channels kommunizieren. Sie werden eine Pipeline erstellen, in der Nachrichten zwischen verschiedenen Verarbeitungsstufen fließen, wobei jede Stufe gleichzeitig ausgeführt wird.

Sie werden Ihren Code auf zwei Dateien verteilen:

  • relay.go: Definieren Sie Ihre Nachrichtenverarbeitungs-Pipeline.

    Erstellen Sie ein Message-Struct mit den Feldern ID (int) und Content (string).

    Implementieren Sie drei Funktionen, die verschiedene Stufen Ihrer Pipeline darstellen:

    • Producer(messages []Message, out chan Message) - Nimmt einen Slice von Nachrichten entgegen und sendet jede einzelne an den Output-Channel. Schließen Sie nach dem Senden aller Nachrichten den Channel, um den Abschluss zu signalisieren.
    • Transformer(in chan Message, out chan Message) - Empfängt Nachrichten vom Input-Channel, wandelt den Inhalt jeder Nachricht in Großbuchstaben um und sendet die transformierte Nachricht an den Output-Channel. Wenn der Input-Channel geschlossen wird (erkannt durch die Empfangsform mit zwei Werten), schließen Sie den Output-Channel.
    • Consumer(in chan Message) []string - Empfängt alle Nachrichten vom Input-Channel und sammelt sie in einem Slice von formatierten Strings. Jeder String sollte dem Format folgen: "Message %d: %s" (wobei %d die ID und %s der Content ist). Geben Sie den Slice zurück, wenn der Channel geschlossen wird.
  • main.go: Richten Sie die Pipeline ein und orchestrieren Sie den gleichzeitigen Nachrichtenfluss.

    Lesen Sie die Anzahl der Nachrichten ein, und lesen Sie dann die ID und den Inhalt jeder Nachricht. Erstellen Sie die Nachrichten und richten Sie zwei Channels ein, um Ihre drei Pipeline-Stufen zu verbinden. Starten Sie den Producer und den Transformer als Goroutinen und führen Sie dann den Consumer in der Haupt-Goroutine aus, um die Ergebnisse zu sammeln. Geben Sie jedes Ergebnis in einer separaten Zeile aus.

Die folgenden Eingaben werden bereitgestellt:

  • Zeile 1: Anzahl der Nachrichten (Ganzzahl)
  • Folgende Zeilen: Für jede Nachricht zwei Zeilen - die Nachrichten-ID (Ganzzahl), dann ihr Inhalt (String)

Zum Beispiel, gegeben:

2
1
hello world
2
go channels

Ihre Ausgabe sollte sein:

Message 1: HELLO WORLD
Message 2: GO CHANNELS

Die Pipeline fließt wie folgt: Producer sendet Nachrichten → Transformer wandelt in Großbuchstaben um → Consumer sammelt und formatiert die Ergebnisse. Jeder Pfeil stellt einen Channel dar, der gleichzeitige Stufen verbindet. Verwenden Sie das strings-Paket für die Umwandlung in Großbuchstaben.

Spickzettel

Channels sind Gos primärer Mechanismus für die Kommunikation zwischen Goroutinen. Erstellen Sie einen Channel mit make und dem Schlüsselwort chan:

messages := make(chan string)

Verwenden Sie den Pfeil-Operator <-, um Werte zu senden und zu empfangen. Der Pfeil zeigt in die Richtung des Datenflusses:

messages <- "hello"  // an Channel senden
msg := <-messages    // von Channel empfangen

Standardmäßig blockieren Sende- und Empfangsvorgänge, bis die Gegenseite bereit ist, was eine integrierte Synchronisierung ermöglicht:

func main() {
    messages := make(chan string)
    
    go func() {
        messages <- "hello"  // an Channel senden
    }()
    
    msg := <-messages  // von Channel empfangen
    fmt.Println(msg)   // Ausgabe: hello
}

Schließen Sie einen Channel, um zu signalisieren, dass keine weiteren Werte gesendet werden. Empfänger können das Schließen mithilfe der Form des Empfangs mit zwei Werten erkennen:

close(messages)

msg, ok := <-messages
if !ok {
    fmt.Println("Channel closed")
}

Channels sind typisiert – ein chan string kann nur Strings übertragen, was Typsicherheit zur Kompilierzeit bietet.

Probier es selbst

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)

	// Anzahl der Nachrichten lesen
	nLine, _ := reader.ReadString('\n')
	n, _ := strconv.Atoi(strings.TrimSpace(nLine))

	// Nachrichten lesen
	messages := make([]Message, n)
	for i := 0; i < n; i++ {
		idLine, _ := reader.ReadString('\n')
		id, _ := strconv.Atoi(strings.TrimSpace(idLine))
		contentLine, _ := reader.ReadString('\n')
		content := strings.TrimSpace(contentLine)
		messages[i] = Message{ID: id, Content: content}
	}

	// TODO: Zwei Kanäle erstellen, um die Pipeline-Stufen zu verbinden

	// TODO: Producer als Goroutine starten

	// TODO: Transformer als Goroutine starten

	// TODO: Consumer in der Haupt-Goroutine ausführen und Ergebnisse sammeln

	// TODO: Jedes Ergebnis in einer separaten Zeile ausgeben
}
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung