Canaux tamponnés
Capacité, fermeture des canaux et parcours d’un canal avec range
Canaux tamponnés est une leçon Go Academy gratuite sur CoddyKit. Ceci est la leçon 3 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Go Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Go Academy comprend 4 leçons au total.
Qu'est-ce qu'un canal avec tampon ?
Un canal avec tampon possède une capacité — les envois ne sont pas bloqués tant qu'il reste de la place dans le tampon. Le canal fonctionne comme une file d'attente :
package main
import "fmt"
func main() {
ch := make(chan int, 3) // capacity 3
ch <- 1 // does not block — buffer has room
ch <- 2 // does not block
ch <- 3 // does not block
// ch <- 4 // would block — buffer full
fmt.Println(<-ch) // 1
fmt.Println(<-ch) // 2
fmt.Println(<-ch) // 3
}Canal avec tampon comme file d'attente
Les canaux avec tampon implémentent une file d'attente FIFO entre les goroutines :
package main
import ("fmt"; "sync")
func producer(ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 1; i <= 5; i++ {
ch <- i
fmt.Printf("produced %d\n", i)
}
}
func main() {
ch := make(chan int, 2) // buffer 2 — producer runs ahead
var wg sync.WaitGroup
wg.Add(1)
go producer(ch, &wg)
wg.Wait()
close(ch)
for v := range ch { fmt.Printf("consumed %d\n", v) }
}len() et cap() sur les canaux
Examinez la taille actuelle et la capacité d'un canal avec tampon :
package main
import "fmt"
func main() {
ch := make(chan string, 5)
ch <- "a"
ch <- "b"
ch <- "c"
fmt.Println("cap:", cap(ch)) // 5
fmt.Println("len:", len(ch)) // 3 — items currently buffered
<-ch
fmt.Println("len:", len(ch)) // 2
}Dissociation du producer et du consumer
Un tampon dissocie la vitesse du producer de celle du consumer. Le producer peut prendre de l'avance jusqu'à la taille du tampon avant de se bloquer :
package main
import ("fmt"; "sync"; "time")
func produce(ch chan<- int, wg *sync.WaitGroup) {
defer wg.Done()
for i := 0; i < 5; i++ {
ch <- i
}
}
func consume(ch <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for v := range ch {
time.Sleep(10 * time.Millisecond) // slower consumer
fmt.Println("consumed:", v)
}
}
func main() {
ch := make(chan int, 3)
var wg sync.WaitGroup
wg.Add(2)
go produce(ch, &wg)
go consume(ch, &wg) // BUG: produce closes before consume sees all
// In practice, coordinate close carefully
fmt.Println("decoupled")
}Sémaphore avec un canal avec tampon
Un canal avec tampon de capacité N peut limiter à N le nombre de goroutines concurrentes — un sémaphore simple :
package main
import ("fmt"; "sync"; "time")
func main() {
sem := make(chan struct{}, 3) // max 3 concurrent
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
i := i
go func() {
defer wg.Done()
sem <- struct{}{} // acquire
defer func() { <-sem }() // release
fmt.Printf("job %d running\n", i)
time.Sleep(50 * time.Millisecond)
}()
}
wg.Wait()
}Fermeture d'un canal avec tampon
La fermeture d'un canal avec tampon permet aux récepteurs de vider les valeurs restantes du tampon avant de détecter la fermeture :
package main
import "fmt"
func main() {
ch := make(chan int, 5)
for i := 1; i <= 3; i++ { ch <- i }
close(ch)
// Drain all buffered values after close:
for v := range ch {
fmt.Println(v) // 1, 2, 3
}
// range exits after channel closed and drained
}Avec ou sans tampon : comment choisir
Guide de décision :
- Sans tampon : transfert synchrone garanti, ordre strict, synchronisation par rendez-vous
- Avec tampon : dissociation des vitesses du producer et du consumer, réduction des blocages, implémentation de sémaphores, collecte de N résultats
- Privilégiez les canaux sans tampon — n'ajoutez un tampon que si vous pouvez justifier sa taille
- Un tampon trop petit → les blocages persistent ; trop grand → il masque les erreurs
Collecte de résultats avec un canal avec tampon
Utilisez un canal avec tampon pour collecter les résultats de goroutines parallèles sans bloquer :
package main
import ("fmt"; "sync")
func square(n int) int { return n * n }
func main() {
nums := []int{1, 2, 3, 4, 5}
results := make(chan int, len(nums)) // buffer = goroutine count
var wg sync.WaitGroup
for _, n := range nums {
wg.Add(1)
n := n
go func() {
defer wg.Done()
results <- square(n)
}()
}
wg.Wait()
close(results)
for r := range results { fmt.Println(r) }
}Fuite de goroutine avec un tampon plein
Si le tampon est plein et qu'aucun lecteur n'existe, le sender reste bloqué indéfiniment — une fuite de goroutine :
package main
import ("fmt"; "time"; "runtime")
func main() {
ch := make(chan int, 2)
// Start goroutine that fills buffer and then blocks
go func() {
ch <- 1
ch <- 2
ch <- 3 // blocks: buffer full, no receiver
fmt.Println("never reached")
}()
time.Sleep(50 * time.Millisecond)
fmt.Println("goroutines:", runtime.NumGoroutine()) // 2 — leaked
}time.After comme canal avec tampon
time.After renvoie un <-chan time.Time avec un tampon de taille 1. L'environnement d'exécution y envoie une valeur après la durée indiquée, puis le canal est récupéré par le ramasse-miettes :
package main
import ("fmt"; "time")
func doWithTimeout(work func() string) (string, bool) {
result := make(chan string, 1)
go func() { result <- work() }()
select {
case r := <-result:
return r, true
case <-time.After(100 * time.Millisecond):
return "", false
}
}
func main() {
r, ok := doWithTimeout(func() string {
time.Sleep(50 * time.Millisecond)
return "done"
})
fmt.Println(r, ok)
}Vérification rapide
Que se passe-t-il lorsque vous envoyez une valeur vers un canal avec tampon dont la capacité est déjà atteinte ?
Récapitulatif : canaux avec tampon
Résumé :
make(chan T, N)crée un canal avec tampon de capacité N- Les envois sont bloqués uniquement lorsque le tampon est plein ; les réceptions sont bloquées uniquement lorsqu'il est vide
len(ch)— éléments actuels ;cap(ch)— capacité- Utilisez-les pour dissocier les producers et les consumers, collecter des résultats parallèles et implémenter des sémaphores
- La fermeture permet de vider le tampon avant EOF ;
range chgère cela automatiquement
Questions Fréquemment Posées
La leçon « Canaux tamponnés » est-elle gratuite ?
Oui — le texte complet de « Canaux tamponnés » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Go Academy, passe à CoddyKit PRO. Le cours Go Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Canaux tamponnés » ?
Capacité, fermeture des canaux et parcours d’un canal avec range Tu pratiques Go Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer Go Academy ?
Aucune expérience préalable n'est requise. Go Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 3 sur 4.
Combien de temps prend la leçon « Canaux tamponnés » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon Go Academy ?
Oui. Chaque leçon Go Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Lancer des goroutines
- Canaux non tamponnés
- Canaux tamponnés
- Direction des canaux et modèles de pipeline