Menu
Coddy logo textTech

Channels & Kommunikation

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

Kanäle sind Gos wichtigster Mechanismus für die Kommunikation zwischen goroutines. Anstatt Speicher direkt gemeinsam zu nutzen, senden und empfangen goroutines Werte über Kanäle, ganz im Sinne der Philosophie von Go: „Kommuniziere nicht durch das Teilen von Speicher; teile Speicher durch Kommunikation.“

Erstelle einen Kanal mit der Funktion make und dem Schlüsselwort chan:

messages := make(chan string)

Verwende den Pfeiloperator <-, 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 Kanal senden
    }()
    
    msg := <-messages  // von Kanal empfangen
    fmt.Println(msg)   // Ausgabe: hello
}

Standardmäßig senden und empfangen sie blockierend, bis die andere Seite bereit ist. Wenn die Goroutine "hello" sendet, wartet sie, bis main zum Empfangen bereit ist. Dieses blockierende Verhalten bietet eine integrierte Synchronisierung: Kein time.Sleep erforderlich.

Du kannst einen Kanal 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 Zeichenketten übertragen. Diese Typsicherheit stellt sicher, dass Goroutinen mit den richtigen Datentypen kommunizieren, und erkennt Fehler zur Kompilierzeit statt zur Laufzeit.

challenge icon

Aufgabe

Einfach

Erstellen wir ein Nachrichtenweiterleitungssystem, das demonstriert, wie Goroutinen über Kanäle kommunizieren. Du erstellst eine Pipeline, in der Nachrichten zwischen verschiedenen Verarbeitungsstufen fließen, wobei jede Stufe gleichzeitig ausgeführt wird.

Du organisierst deinen Code über zwei Dateien:

  • relay.go: Definiere deine Nachrichtenverarbeitungspipeline.

    Erstelle eine Message-Struktur mit den Feldern ID (int) und Content (string).

    Implementiere drei Funktionen, die verschiedene Stufen deiner Pipeline darstellen:

    • Producer(messages []Message, out chan Message) – Nimmt ein Nachrichten-Slice entgegen und sendet jede Nachricht an den Ausgabekanal. Nachdem alle Nachrichten gesendet wurden, schließe den Kanal, um den Abschluss zu signalisieren.
    • Transformer(in chan Message, out chan Message) – Empfängt Nachrichten vom Eingabekanal, wandelt den Inhalt jeder Nachricht in Großbuchstaben um und sendet die transformierte Nachricht an den Ausgabekanal. Wenn der Eingabekanal geschlossen ist (erkannt mithilfe der Empfangsform mit zwei Werten), schließe den Ausgabekanal.
    • Consumer(in chan Message) []string – Empfängt alle Nachrichten vom Eingabekanal und sammelt sie in einem Slice formatierter Zeichenketten. Jede Zeichenkette sollte dem Format Message [ID]: [Content] folgen. Gib das Slice zurück, wenn der Kanal geschlossen ist.
  • main.go: Richte die Pipeline ein und steuere den gleichzeitigen Nachrichtenfluss.

    Lies die Anzahl der Nachrichten und anschließend die ID und den Inhalt jeder Nachricht ein. Erstelle die Nachrichten und richte zwei Kanäle ein, um deine drei Pipelinestufen zu verbinden. Starte Producer und Transformer als Goroutinen und führe anschließend Consumer in der main-Goroutine aus, um die Ergebnisse zu sammeln. Gib jedes Ergebnis in einer eigenen 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), anschließend ihr Inhalt (Zeichenkette)

Beispiel für folgende Eingabe:

2
1
hello world
2
go channels

Deine Ausgabe sollte folgendermaßen aussehen:

Message 1: HELLO WORLD
Message 2: GO CHANNELS

Die Pipeline funktioniert folgendermaßen: Producer sendet Nachrichten → Transformer wandelt sie in Großbuchstaben um → Consumer sammelt und formatiert die Ergebnisse. Jeder Pfeil stellt einen Kanal dar, der gleichzeitig ausgeführte Stufen verbindet. Verwende das Paket strings für die Umwandlung in Großbuchstaben.

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: Erstelle zwei Channels, um die Pipeline-Stufen zu verbinden

	// TODO: Starte Producer als Goroutine

	// TODO: Starte Transformer als Goroutine

	// TODO: Führe Consumer in der main-Goroutine aus und sammle die Ergebnisse

	// TODO: Gib jedes Ergebnis in einer eigenen Zeile aus
}
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

Übe selbstständig: Online-Go-Compiler