Menu
Coddy logo textTech

Canali e comunicazione

Fa parte della sezione Programmazione orientata agli oggetti del percorso GO di Coddy. Lezione 60 di 107.

I canali sono il meccanismo principale di Go per la comunicazione tra goroutine. Invece di condividere direttamente la memoria, le goroutine inviano e ricevono valori attraverso i canali, seguendo la filosofia di Go: «Non comunicare condividendo la memoria; condividi la memoria comunicando.»

Crea un canale usando la funzione make con la parola chiave chan:

messages := make(chan string)

Usa l’operatore freccia <- per inviare e ricevere valori. La freccia indica la direzione del flusso di dati:

func main() {
    messages := make(chan string)
    
    go func() {
        messages <- "hello"  // invia al canale
    }()
    
    msg := <-messages  // ricevi dal canale
    fmt.Println(msg)   // Uscita: hello
}

Per impostazione predefinita, gli invii e le ricezioni bloccano finché l’altra parte non è pronta. Quando la goroutine invia "hello", aspetta finché main non è pronta a ricevere. Questo comportamento bloccante fornisce una sincronizzazione integrata: non serve time.Sleep.

Puoi chiudere un canale per segnalare che non verranno inviati altri valori. I destinatari possono rilevarlo:

close(messages)

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

I canali sono tipizzati: un chan string può trasportare solo stringhe. Questa sicurezza dei tipi garantisce che le goroutine comunichino con i tipi di dati corretti, rilevando gli errori in fase di compilazione anziché durante l'esecuzione.

challenge icon

Sfida

Facile

Creiamo un sistema di inoltro dei messaggi che mostra come le goroutine comunicano attraverso i canali. Creerai una pipeline in cui i messaggi fluiscono tra diverse fasi di elaborazione, ciascuna eseguita contemporaneamente.

Organizzerai il codice in due file:

  • relay.go: definisci la pipeline di elaborazione dei messaggi.

    Crea una struct Message con i campi ID (int) e Content (string).

    Implementa tre funzioni che rappresentano le diverse fasi della pipeline:

    • Producer(messages []Message, out chan Message) - Riceve una slice di messaggi e invia ciascuno al canale di output. Dopo aver inviato tutti i messaggi, chiudi il canale per segnalare il completamento.
    • Transformer(in chan Message, out chan Message) - Riceve i messaggi dal canale di input, trasforma in maiuscolo il contenuto di ciascun messaggio e invia il messaggio trasformato al canale di output. Quando il canale di input viene chiuso (rilevato usando la forma di ricezione a due valori), chiudi il canale di output.
    • Consumer(in chan Message) []string - Riceve tutti i messaggi dal canale di input e li raccoglie in una slice di stringhe formattate. Ogni stringa deve seguire il formato: Message [ID]: [Content]. Restituisci la slice quando il canale viene chiuso.
  • main.go: configura la pipeline e coordina il flusso concorrente dei messaggi.

    Leggi il numero di messaggi, quindi leggi l'ID e il contenuto di ciascun messaggio. Crea i messaggi e configura due canali per collegare le tre fasi della pipeline. Avvia Producer e Transformer come goroutine, quindi esegui Consumer nella goroutine principale per raccogliere i risultati. Stampa ogni risultato su una riga separata.

Verranno forniti i seguenti input:

  • Riga 1: numero di messaggi (intero)
  • Righe successive: per ogni messaggio, due righe: l'ID del messaggio (intero), poi il suo contenuto (stringa)

Per esempio, dato:

2
1
hello world
2
go channels

L'output dovrebbe essere:

Message 1: HELLO WORLD
Message 2: GO CHANNELS

La pipeline funziona così: Producer invia i messaggi → Transformer li converte in maiuscolo → Consumer raccoglie e formatta i risultati. Ogni freccia rappresenta un canale che collega fasi concorrenti. Usa il pacchetto strings per la trasformazione in maiuscolo.

Provalo tu

package main

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

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

	// Leggi il numero di messaggi
	nLine, _ := reader.ReadString('\n')
	n, _ := strconv.Atoi(strings.TrimSpace(nLine))

	// Leggi i messaggi
	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: Crea due canali per collegare le fasi della pipeline

	// TODO: Avvia Producer come goroutine

	// TODO: Avvia Transformer come goroutine

	// TODO: Esegui Consumer nella goroutine main e raccogli i risultati

	// TODO: Stampa ogni risultato su una riga separata
}
quiz iconMettiti alla prova

Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.

Tutte le lezioni di Programmazione orientata agli oggetti

Esercitati da solo: Compilatore Go online