Leçons du module (2/5)
Channels : communication typée
Les canaux sont le mécanisme idiomatique de communication entre goroutine. Allez la philosophie (Rob Pike) :
"Ne communiquez pas en partageant la mémoire ; partagez la mémoire en communiquant."
Un canal est une file d'attente FIFO typée, de type sécurisé et sûre à utiliser
concurrent. Combiné avec go, il s'agit du principal élément constitutif du
Allez en compétition.
Créer, envoyer, recevoir
ch := make(chan int) // canale di int, unbuffered
go func() {
ch <- 42 // invia (può bloccare)
}()
v := <-ch // ricevi (può bloccare)
fmt.Println(v) // 42Syntaxe :
make(chan T)oumake(chan T, N)pour mis en mémoire tampon.ch <- venvoyer.v := <-chreçoit.v, ok := <-chreçoit avec flag (ok = falsesi le canal est fermé ET vide).
Unbuffered : rendez-vous
Un canal non tamponné (capacité 0) bloque :
- l'expéditeur jusqu'à ce qu'un destinataire soit prêt ;
- le récepteur jusqu'à ce qu'un expéditeur soit prêt.
Il s'agit d'un rendez-vous synchrone : utile comme "signal" ou pour s'assurer que le la valeur a été livrée.
Buffered : file d'attente jusqu'à N
ch := make(chan int, 3)
ch <- 1 // non blocca
ch <- 2 // non blocca
ch <- 3 // non blocca
ch <- 4 // BLOCCA: il buffer è pienoL'expéditeur bloque uniquement lorsque le tampon est plein ; le récepteur seul quand il est vide.
proche et à distance
L'expéditeur ferme le canal lorsqu'il n'y a plus de valeurs :
ch := make(chan int, 3)
ch <- 1
ch <- 2
ch <- 3
close(ch)
for v := range ch { // termina quando ch è chiuso E vuoto
fmt.Println(v)
}for range sur un canal itère jusqu'à ce que le canal soit fermé (et vidé).
C'est le modèle le plus propre : « consommer tout ce qui vient ».
Directionnalité dans les signatures
Les paramètres de fonction peuvent limiter la direction :
func producer(out chan<- int) { // solo invio
out <- 1
close(out)
}
func consumer(in <-chan int) { // solo ricezione
for v := range in {
fmt.Println(v)
}
}chan<- T = envoi uniquement, <-chan T = réception uniquement. Le canal "bidirectionnel"
chan T peut être transmis aux deux (conversion implicite). Augmentation
clarté et évite les erreurs.
Modèles courants (aperçu)
- Groupe de travailleurs : N goroutines consomment à partir de
jobs <-chan T, produisent surresults chan<- R. - Pipeline : étapes connectées par canal.
- Signal terminé : canal
chan struct{}fermé pour signaler "stop".
done := make(chan struct{})
go func() {
<-done // blocca finché qualcuno chiude done
cleanup()
}()
close(done) // segnale di stopchan struct{} est le canal « signal » : aucun octet de charge utile, uniquement
synchronisation.
Essayez-le vous-même
Créez un canal ch d'int sans tampon, envoyez 42 depuis une goroutine, recevez en main et imprimez.
Afficher l'indice
Sans mise en mémoire tampon, l'expéditeur et le destinataire se synchronisent.
Solution disponible après 3 tentatives
Envoyez 1,2,3 sur un canal tamponné, fermez-le, puis imprimez le tout avec for-range.
Afficher l'indice
`for range` sur un canal se termine lorsque le canal est fermé et vidé.
Solution disponible après 3 tentatives
Que fait un canal UNBUFFERED lorsque l'expéditeur envoie mais qu'aucun récepteur n'est prêt ?
ch := make(chan int)
ch <- 1 // ?Récapitulatif
- Channel = file d'attente typée FIFO, sécurisée entre les goroutines.
- Unbuffered : rendez-vous (synchronisation de l'expéditeur et du destinataire).
- Buffered : découplage, blocage uniquement lorsqu'il est plein/vide.
close(ch): uniquement l'expéditeur ;for rangeconsomme jusqu'à la fermeture.- Directionnalité :
chan<- T(envoi uniquement),<-chan T(réception uniquement). chan struct{}comme canal de signal pour une synchronisation pure.