Maison > Article > développement back-end > Explication détaillée du canal Golang Chan
Ce qui suit est une introduction détaillée à Golang tirée de la tutoriel Golang colonne sur la chaîne Chan, j'espère qu'elle sera utile aux amis dans le besoin !
Regardons d'abord les threads, également appelés goroutine en golang
Avant de lire cet article, nous devons comprendre la concurrence et le parallélisme. Le fil de Golang est un mécanisme de concurrence, pas de parallélisme. Vous pouvez rechercher sur Internet les différences entre eux. Il existe de nombreuses introductions en ligne.
Regardons d'abord un exemple
import( "fmt" ) funcmain(){ go fmt.Println("1") fmt.Println("2") }
En golang, vous pouvez créer un fil de discussion en utilisant le mot-clé go suivi d'une fonction. Cette dernière fonction peut être une fonction déjà écrite, ou elle peut être une fonction anonyme
funcmain(){ var i=3 go func(a int) { fmt.Println(a) fmt.Println("1") }(i) fmt.Println("2")}
Le code ci-dessus crée une fonction anonyme, et passe également un paramètre i, qui est entre parenthèses en dessous du i est le paramètre réel et a est le paramètre formel.
Le code ci-dessus peut-il donc imprimer 1, 2 et 3 comme prévu ? Laissez-moi vous dire que non, le programme ne peut en imprimer que 2. Je publierai le code correct ci-dessous
import( "fmt" "time" )funcmain(){ var i = 3 go func(a int) { fmt.Println(a) fmt.Println("1") }(i) fmt.Println("2") time.Sleep(1 * time.Second)}
Je viens d'ajouter une ligne de code à la fin pour faire dormir le thread principal pendant une seconde, et le programme imprimera 2, 3 et 1 dans l'ordre
.
Alors pourquoi cela se produit-il ? Étant donné que le programme exécutera d'abord le thread principal, une fois l'exécution du thread principal terminée, le programme se terminera immédiatement, ne laissant aucun temps supplémentaire pour exécuter le thread enfant. Si vous laissez le thread principal dormir pendant 1 seconde à la fin du programme, le programme aura suffisamment de temps pour exécuter le thread enfant.
Le fil de discussion est ici en premier, jetons un coup d'œil à la chaîne.
Le canal est également appelé canal. Comme son nom l'indique, la fonction du canal est de transférer des données entre plusieurs threads.
Créer un canal sans tampon
chreadandwrite :=make(chan int)
chonlyread := make(<-chan int) //Créer un canal en lecture seule
chonlywrite := make(chan<- int) //Créer un canal en écriture seule
Regardons un exemple :
ch :=make(chan int) ch <- 1 go func() { <-ch fmt.Println("1") }() fmt.Println("2")
Une erreur se produira lors de l'exécution de ce code : erreur fatale : tous les goroutines sont endormies - impasse !
Cette erreur signifie que le thread est bloqué dans une impasse et que le programme ne peut pas continuer à s'exécuter. Alors quelle est la cause de cette erreur ?
Nous avons créé un canal sans tampon, puis attribué une valeur au canal. Le programme est tombé dans une impasse une fois la mission terminée. Parce que notre canal est sans tampon, c'est-à-dire synchrone, le programme sera bloqué avant que le canal puisse être lu une fois l'affectation terminée. Voici un concept très important : le mécanisme du canal est premier entré, premier sorti. Si vous attribuez une valeur au canal, vous devez lire sa valeur, sinon cela provoquera un blocage. Bien entendu, cela n'est valable que pour les canaux non tamponnés. . Pour les canaux mis en mémoire tampon, l'expéditeur bloquera jusqu'à ce que les données soient copiées dans le tampon ; si le tampon est plein, l'expéditeur ne pourra sortir de l'état de blocage qu'après que le récepteur aura supprimé les données.
Il existe deux solutions à l'exemple ci-dessus :
1. Ajoutez un tampon au canal, puis laissez le thread principal dormir pendant une seconde à la fin du programme. comme suit :
ch :=make(chan int,1) ch <- 1 go func() { v := <-ch fmt.Println(v) }() time.Sleep(1 * time.Second) fmt.Println("2")
Dans ce cas, le programme imprimera 1, 2 dans l'ordre
2. Mettez la ligne de code ch<-1 derrière le code du sous-thread Le code. est le suivant :
ch :=make(chan int) go func() { v := <-ch fmt.Println(v) }() ch <- 1 fmt.Println("2")
Ce n'est pas nécessaire ici. Laissez le thread principal dormir, car une fois qu'une valeur est attribuée au canal dans le thread principal, le thread principal se bloquera jusqu'à ce que la valeur du canal soit supprimée. dans le fil enfant.
Enfin, regardons un exemple de producteur et de consommateur :
import ( "fmt" "time")func produce(p chan<- int) { for i := 0; i < 10; i++ { p <- i fmt.Println("send:", i) } }func consumer(c <-chan int) { for i := 0; i < 10; i++ { v := <-c fmt.Println("receive:", v) } }func main() { ch := make(chan int) go produce(ch) go consumer(ch) time.Sleep(1 * time.Second) }
Dans ce code, comme le canal n'est pas tamponné, lorsque le producteur attribue une valeur au canal, le producteur Le thread se bloquera jusqu'à ce que le thread consommateur retire les données du canal. Après que le consommateur ait extrait les données pour la première fois, le thread du consommateur sera également bloqué lors du cycle suivant car le producteur n'a pas encore stocké les données. À ce moment-là, le programme exécutera le thread du producteur. De cette façon, le programme bascule en permanence entre les threads consommateur et producteur jusqu'à la fin de la boucle.
Regardons un autre exemple avec buffering :
import ( "fmt" "time")func produce(p chan<- int) { for i := 0; i < 10; i++ { p <- i fmt.Println("send:", i) } }func consumer(c <-chan int) { for i := 0; i < 10; i++ { v := <-c fmt.Println("receive:", v) } }func main() { ch := make(chan int, 10) go produce(ch) go consumer(ch) time.Sleep(1 * time.Second) }
Dans ce programme, le tampon peut stocker 10 entiers de type int Lors de l'exécution du thread producteur, le thread ne le bloquera pas et le stockera. 10 entiers dans le canal à la fois. Lors de la lecture, il est également lu en une seule fois.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!