Maison >développement back-end >Golang >Comprendre le comportement du canal de blocage Golang en écrivant plusieurs fois sur le canal
Dans cet article, l'éditeur PHP Youzi vous présentera comment comprendre le comportement de Golang consistant à bloquer le canal en écrivant plusieurs fois sur le canal. Dans Golang, les canaux sont un mécanisme important pour transmettre des données entre coroutines. Lorsqu'un canal est plein, les opérations d'écriture sont bloquées jusqu'à ce que le canal soit libre. Nous démontrerons ce comportement avec un exemple simple et expliquerons comment fonctionnent les canaux de blocage et comment les utiliser. Que vous soyez un développeur Golang débutant ou expérimenté, vous pouvez acquérir des connaissances utiles et une expérience pratique grâce à cet article. commençons!
Je suis nouveau sur Golang et j'essaie de comprendre la concurrence dans le langage. J'ai un code qui pousse certaines valeurs vers un canal puis les lit.
package main import ( "log" "time" ) func Greet2(c chan string) { // logging to Stdout is not an atomic operation // so artificially, sleep for some time time.Sleep(2 * time.Second) // 5. until below line reads and unblock the channel log.Printf("5. Read Greet2:: %s\n\n", <-c) } func Greet(c chan string) { // 4. Push a new value to the channel, this will block // Process will look for other go routines to execute log.Printf("4. Add 'Greet::John' to the channel, block until it is read. Remember, 'Greet' goroutine will block and only other goroutines can run even though this go routine can pull the value out from the channel.\n\n") c <- "Greet::John!" // 8. This statement will never execute log.Printf("8. Read Greet:: %s !\n\n", <-c) } func main() { c := make(chan string) log.Println("1. Main start") // 2. Both go routine will be declared and both will // for a value to be inserted in the channel log.Println("2. Declare go routines.\n\n") go Greet(c) go Greet2(c) // 3. write will block log.Println("3. Add 'main::Hello' to the channel, block until it is read. Remember, 'main' goroutine will block and only other goroutines can run even though this go routine can pull the value out from the channel.\n\n") c <- "main::Hello" // Sleep to give time goroutines to execute time.Sleep(time.Second) // 6. read the channel value. log.Printf("6. Read main:: %s \n\n", <-c) // 7. Insert a new value to the channel log.Println("7. Add 'main::Bye' to the channel, block until it is read.\n") c <- "main::Bye" // Sleep to give time goroutines to execute time.Sleep(time.Second) log.Println("9. Main stop") }
Le résultat du programme ci-dessus est
2023/09/02 21:58:07 1. Main start 2023/09/02 21:58:07 2. Declare go routines. 2023/09/02 21:58:07 3. Add 'main::Hello' to the channel, block until it is read. Remember, 'main' goroutine will block and only other goroutines can run even though this go routine can pull the value out from the channel. 2023/09/02 21:58:07 4. Add 'Greet::John' to the channel, block until it is read. Remember, 'Greet' goroutine will block and only other goroutines can run even though this go routine can pull the value out from the channel. 2023/09/02 21:58:10 5. Read Greet2:: main::Hello 2023/09/02 21:58:11 6. Read main:: Greet::John! 2023/09/02 21:58:11 7. Add 'main::Bye' to the channel, block until it is read. 2023/09/02 21:58:11 8. Read Greet:: main::Bye ! 2023/09/02 21:58:12 9. Main stop
Je ne comprends pas pourquoi 4.
(另一个写入通道)在 5.
(第一次从通道读取)之前执行,因为 3.
将阻塞,并且在读取值之前通道不可用来自它(在步骤 5.
中)。我是否误解了阻塞行为,在步骤 3.
中,只有 main
goroutine 块和 Greet
(在步骤 4.
) peut écrire une valeur supplémentaire sur la chaîne ? Une explication dissiperait vraiment ma confusion :)
Bravo, D.D.
Merci pour votre réponse, j'ai créé un programme plus simple à démontrer. Concurrence
package main import ( "fmt" ) func do2(c chan int) { fmt.Println(<-c) } func do(c chan int) { // 4. this statement is trying to write another value "2" to the channel // Channel already contains "1" as the value which has not been read yet. // this statement will wait for "1" to get read and block the execution. // Scheduler will look for other goroutines that can execute. // However, this("do") is blocked as well as "main" is blocked too and // there are no other goroutines to execute. // Hence, will result in a "Deadlock" fatal error. c <- 2 fmt.Println(<-c) } func main() { // 1. Declare a channel c := make(chan int) // 2. Declare "do" goroutine go do(c) // 3. write "1" to the channel // This will block and wait for program's other goroutines to read the value. // however, there is only "do" goroutine is defined can run at this point. // Scheduler, will try to run "do" goroutine. c <- 1 go do2(c) }
Deadlock
peut être résolu en échangeant les instructions c <- 1
et go do2(c)
. 死锁
可以通过交换c <- 1
和go do2(c)
语句来修复。
在 Go 中,当您在通道上发送值时(步骤 3 中的 c <- "main::Hello"
),发送 Goroutine 将阻塞,直到有另一个 Goroutine 准备好从通道接收值。然而,这并不意味着没有其他 goroutine 可以继续执行。在您的代码中, Greet
和 Greet2
c <- "main::Hello"
à l'étape 3), la Goroutine d'envoi se bloquera jusqu'à ce qu'il y ait une autre Goroutine A. prêt à recevoir les valeurs du canal. Cependant, cela ne signifie pas qu’aucune autre goroutine ne peut continuer à s’exécuter. Dans votre code, les c
Permettez-moi de détailler la séquence des événements étape par étape : Greet
和 Greet2
Le programme principal démarre et vous créez une chaîne Greet
或 Greet2
Vous avez déclaré deux goroutines, Greet
解除阻塞并继续执行。它记录消息“4. 将‘Greet::John’添加到频道...”并发送“Greet::John!”在频道上。这会再次阻塞 Greet
Vous envoyez une valeur "main::Hello" sur le canal, qui bloque la goroutine principale jusqu'à ce que d'autres goroutines lisent les données du canal. Cependant, l'un des deux Goroutines (Greet2
Greet
在向通道写入时仍被阻止,而 Greet2
Greet
Main envoie une autre valeur "main::Bye" sur le canal. À ce stade, est toujours bloqué en écriture, il n'enregistre jamais "8. Read Greet:: main::Bye Greet2
碰巧首先被解锁,但也可能是 Greet
!"
🎜La clé pour comprendre le comportement ici est que lorsque vous envoyez une valeur sur un canal, cela déverrouille toutes les goroutines qui attendent de lire les données du canal. L'ordre dans lequel les goroutines en attente sont débloquées n'est pas défini et dépend du planificateur. Dans votre cas, 🎜 se trouve être déverrouillé en premier, mais cela pourrait aussi l'être 🎜. 🎜 🎜En résumé, le comportement que vous observez est tout à fait cohérent avec le fonctionnement des canaux Go, avec la nuance que l'ordre d'exécution entre Goroutines concurrents n'est pas garanti. 🎜
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!