Oui, c'est compliqué, mais il existe quelques règles empiriques qui devraient rendre les choses beaucoup plus simples.
-
préfèrent utiliser des arguments formels pour les canaux que vous passez aux go-routines au lieu d'accéder aux canaux dans la portée globale. Vous pouvez obtenir plus de vérification du compilateur de cette façon, et une meilleure modularité aussi.
-
éviter la lecture et l'écriture sur le même canal dans un go-routine particulier (y compris le "principal"). Sinon, le risque de blocage est beaucoup plus grand.
Voici une version alternative de votre programme, en appliquant ces deux directives. Ce cas démontre plusieurs rédacteurs et un lecteur sur une chaîne :
c := make(chan string)
for i := 1; i <= 5; i++ {
go func(i int, co chan<- string) {
for j := 1; j <= 5; j++ {
co <- fmt.Sprintf("hi from %d.%d", i, j)
}
}(i, c)
}
for i := 1; i <= 25; i++ {
fmt.Println(<-c)
}
http://play.golang.org/p/quQn7xePLw
Il crée les cinq go-routines écrivant sur un seul canal, chacune écrivant cinq fois. La go-routine principale lit les vingt-cinq messages - vous remarquerez que l'ordre dans lequel ils apparaissent n'est souvent pas séquentiel (c'est-à-dire que la concurrence est évidente).
Cet exemple démontre une caractéristique des canaux de Go : il est possible d'avoir plusieurs rédacteurs partageant un canal ; Go intercalera les messages automatiquement.
Il en va de même pour un écrivain et plusieurs lecteurs sur un même canal, comme le montre le deuxième exemple ici :
c := make(chan int)
var w sync.WaitGroup
w.Add(5)
for i := 1; i <= 5; i++ {
go func(i int, ci <-chan int) {
j := 1
for v := range ci {
time.Sleep(time.Millisecond)
fmt.Printf("%d.%d got %d\n", i, j, v)
j += 1
}
w.Done()
}(i, c)
}
for i := 1; i <= 25; i++ {
c <- i
}
close(c)
w.Wait()
Ce site deuxième exemple comprend une attente imposée à la goroutine principale, qui sinon se terminerait rapidement et entraînerait la fin anticipée des cinq autres goroutines. (merci à olov pour cette correction) .
Dans les deux exemples, aucune mise en mémoire tampon n'a été nécessaire. En règle générale, il est bon de considérer la mise en mémoire tampon uniquement comme un moyen d'améliorer les performances. Si votre programme ne se bloque pas sans les tampons, il n'y aura pas de blocage avec tampons non plus (mais l'inverse n'est pas toujours vrai). Ainsi, comme une autre règle de base, commencez sans mise en mémoire tampon, puis ajoutez-la plus tard si nécessaire. .