Blocage des canaux (Channels)
Les étudiants attentifs auront peut-être remarqué que lorsque nous avons présenté les déclarations et l'initialisation des canaux (channels), nous n'avons pas spécifié la capacité du canal :
package main
import "fmt"
func main() {
// Stocke des données entières dans le canal (channel)
ch1 := make(chan int) // Idem ci-dessous
// Stocke des données booléennes dans le canal (channel)
ch2 := make(chan bool)
// Stocke des données de type []int dans le canal (channel)
ch3 := make(chan []int)
fmt.Println(ch1, ch2, ch3)
}
Mais lorsque nous avons démontré les opérations sur les canaux (channels), nous avons spécifié la capacité du canal :
package main
import "fmt"
func main() {
// Spécifie la capacité du canal (channel) à 3
ch := make(chan int, 3)
ch <- 10
ch <- 20
fmt.Println(<-ch)
fmt.Println(<-ch)
}
Pour les canaux (channels) sans capacité spécifiée, on les appelle des canaux non tamponnés (unbuffered channels), qui n'ont pas d'espace tampon.
Si l'émetteur ou le récepteur n'est pas prêt, la première opération sera bloquée jusqu'à ce que l'autre opération soit prête.
chan1 := make(chan int) // Canal non tamponné (unbuffered channel) de type int
Pour les canaux (channels) avec une capacité et un espace tampon spécifiés, on les appelle des canaux tamponnés (buffered channels).
chan2 := make(chan int, 5) // Canal tamponné (buffered channel) de type int avec une capacité de 5
Ils fonctionnent comme une file d'attente, en respectant la règle du Premier Entré, Premier Sorti (First In First Out - FIFO).
Pour les canaux tamponnés (buffered channels), nous pouvons utiliser des opérations d'envoi pour ajouter des éléments à la fin de la file d'attente et des opérations de réception pour supprimer des éléments du début de la file d'attente.
Que se passe-t-il si nous mettons plus de données dans un canal tamponné (buffered channel) que sa capacité? Vérifions cela. Écrivez le code suivant dans le fichier channel1.go
:
cd ~/project
touch channel1.go
package main
import "fmt"
func main() {
ch := make(chan int, 1)
ch <- 10
ch <- 20
fmt.Println("succeed")
}
Exécutez le programme en utilisant la commande suivante :
go run channel1.go
La sortie du programme est la suivante :
fatal error: all goroutines are asleep - deadlock!
Nous constatons que le programme est en blocage (deadlock) car le canal (channel) est déjà plein.
Pour résoudre ce problème, nous pouvons extraire d'abord les données du canal (channel). Écrivez le code suivant dans channel.go
:
package main
import "fmt"
func main() {
ch := make(chan int, 1)
ch <- 10
fmt.Println("Data extracted:", <-ch)
ch <- 20
fmt.Println("succeed")
}
Exécutez le programme en utilisant la commande suivante :
go run channel.go
La sortie du programme est la suivante :
Data extracted: 10
succeed
Nous pouvons utiliser continuellement le canal (channel) avec une capacité limitée en adoptant une stratégie de prendre, utiliser, prendre et utiliser à nouveau.