Menu
Coddy logo textTech

Channels et Communication

Fait partie de la section Programmation Orientée Objet du Journey GO de Coddy — leçon 60 sur 107.

Les canaux (channels) sont le mécanisme principal de Go pour la communication entre les goroutines. Plutôt que de partager directement la mémoire, les goroutines envoient et reçoivent des valeurs via des canaux, en suivant la philosophie de Go : « Ne communiquez pas en partageant la mémoire ; partagez la mémoire en communiquant. »

Créez un canal en utilisant la fonction make avec le mot-clé chan :

messages := make(chan string)

Utilisez l'opérateur flèche <- pour envoyer et recevoir des valeurs. La flèche pointe dans la direction du flux de données :

func main() {
    messages := make(chan string)
    
    go func() {
        messages <- "hello"  // envoyer au canal
    }()
    
    msg := <-messages  // recevoir du canal
    fmt.Println(msg)   // Output: hello
}

Par défaut, les envois et les réceptions sont bloquants jusqu'à ce que l'autre côté soit prêt. Quand la goroutine envoie "hello", elle attend que main soit prêt à recevoir. Ce comportement bloquant fournit une synchronisation intégrée — pas besoin de time.Sleep.

Vous pouvez fermer un canal pour signaler qu'aucune autre valeur ne sera envoyée. Les récepteurs peuvent le détecter :

close(messages)

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

Les channels sont typés — un chan string ne peut transporter que des chaînes de caractères. Cette sécurité de type garantit que les goroutines communiquent avec les bons types de données, permettant de détecter les erreurs à la compilation plutôt qu'à l'exécution.

challenge icon

Défi

Facile

Construisons un système de relais de messages qui démontre comment les goroutines communiquent via des canaux. Vous allez créer un pipeline où les messages circulent entre différentes étapes de traitement, chaque étape s'exécutant de manière concurrente.

Vous organiserez votre code sur deux fichiers :

  • relay.go : Définissez votre pipeline de traitement de messages.

    Créez une structure Message avec les champs ID (int) et Content (string).

    Implémentez trois fonctions qui représentent les différentes étapes de votre pipeline :

    • Producer(messages []Message, out chan Message) - Prend une tranche (slice) de messages et envoie chacun d'eux vers le canal de sortie. Après avoir envoyé tous les messages, fermez le canal pour signaler la fin.
    • Transformer(in chan Message, out chan Message) - Reçoit des messages du canal d'entrée, transforme le contenu de chaque message en majuscules et envoie le message transformé vers le canal de sortie. Lorsque le canal d'entrée est fermé (détecté à l'aide de la forme de réception à deux valeurs), fermez le canal de sortie.
    • Consumer(in chan Message) []string - Reçoit tous les messages du canal d'entrée et les collecte dans une tranche de chaînes de caractères formatées. Chaque chaîne doit suivre le format : "Message %d: %s" (utilisant Message [ID]: [Content]). Retournez la tranche lorsque le canal est fermé.
  • main.go : Configurez le pipeline et orchestrez le flux de messages concurrent.

    Lisez le nombre de messages, puis lisez l'ID et le contenu de chaque message. Créez les messages et configurez deux canaux pour connecter vos trois étapes de pipeline. Lancez le Producer et le Transformer en tant que goroutines, puis exécutez le Consumer dans la goroutine principale pour collecter les résultats. Affichez chaque résultat sur une ligne distincte.

Les entrées suivantes seront fournies :

  • Ligne 1 : Nombre de messages (entier)
  • Lignes suivantes : Pour chaque message, deux lignes - l'ID du message (entier), puis son contenu (chaîne de caractères)

Par exemple, avec :

2
1
hello world
2
go channels

Votre sortie devrait être :

Message 1: HELLO WORLD
Message 2: GO CHANNELS

Le pipeline fonctionne ainsi : Producer envoie les messages → Transformer convertit en majuscules → Consumer collecte et formate les résultats. Chaque flèche représente un canal connectant des étapes concurrentes. Utilisez le package strings pour la transformation en majuscules.

Aide-mémoire

Les canaux (channels) sont le mécanisme principal de Go pour la communication entre les goroutines. Créez un canal en utilisant make avec le mot-clé chan :

messages := make(chan string)

Utilisez l'opérateur flèche <- pour envoyer et recevoir des valeurs. La flèche pointe dans la direction du flux de données :

messages <- "hello"  // envoyer au canal
msg := <-messages    // recevoir du canal

Par défaut, les envois et les réceptions sont bloquants jusqu'à ce que l'autre côté soit prêt, offrant ainsi une synchronisation intégrée :

func main() {
    messages := make(chan string)
    
    go func() {
        messages <- "hello"  // envoyer au canal
    }()
    
    msg := <-messages  // recevoir du canal
    fmt.Println(msg)   // Output: hello
}

Fermez un canal pour signaler qu'aucune autre valeur ne sera envoyée. Les récepteurs peuvent détecter la fermeture en utilisant la forme de réception à deux valeurs :

close(messages)

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

Les canaux sont typés — un chan string ne peut transporter que des chaînes de caractères, offrant ainsi une sécurité de type à la compilation.

Essayez vous-même

package main

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

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

	// Lire le nombre de messages
	nLine, _ := reader.ReadString('\n')
	n, _ := strconv.Atoi(strings.TrimSpace(nLine))

	// Lire les messages
	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: Créer deux canaux pour connecter les étapes du pipeline

	// TODO: Lancer Producer en tant que goroutine

	// TODO: Lancer Transformer en tant que goroutine

	// TODO: Exécuter Consumer dans la goroutine principale et collecter les résultats

	// TODO: Imprimer chaque résultat sur une ligne séparée
}
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation Orientée Objet