Maison  >  Article  >  développement back-end  >  Le mécanisme de blocage du Buffered Channel de Go

Le mécanisme de blocage du Buffered Channel de Go

WBOY
WBOYavant
2024-02-10 14:30:111024parcourir

Go 的 Buffered Channel 的阻塞机制

Dans le langage Go, il existe un type de canal spécial appelé Buffered Channel, qui stocke un certain nombre d'éléments dans le canal. Lorsque le nombre d'éléments dans le canal atteint la limite supérieure définie, l'opération d'écriture sera bloquée jusqu'à ce que d'autres coroutines lisent les éléments du canal. Au contraire, lorsque le nombre d'éléments dans le canal est nul, l'opération de lecture sera également bloquée jusqu'à ce qu'une autre coroutine écrive des éléments dans le canal. Ce mécanisme de blocage peut contrôler efficacement la synchronisation et la communication entre les coroutines. Dans cet article, nous présenterons en détail le mécanisme de blocage de Buffered Channel dans le langage Go.

Contenu de la question

Dans "Tour of Go", l'exemple de code est donné comme ceci :

package main

import "fmt"

func main() {
    ch := make(chan int, 2)
    ch <- 1
    ch <- 2
    fmt.Println(<-ch)
    fmt.Println(<-ch)
}

Il s'exécute bien et s'imprime

1
2

Ce comportement diffère de la description de cet exercice, qui indique :

<code>
Sends to a buffered channel block only when the buffer is full. Receives block when the buffer is empty
</code>

dans ch <- 2 行之后,ch is 已满,并且由于我们只运行 1 个单独的 Goroutine,即主 Goroutine,因此该 Goroutine 应该被阻塞,直到 ch is 被接收者消耗,因此代码不应该到达fmt.Println(<-ch) OK, mais je devrais dire quelque chose comme

<code>
fatal error: all goroutines are asleep - deadlock!
</code>

Cependant, comme ce n'est pas le cas, je suis confus et je cherche des conseils.

C'est un autre morceau de code que j'ai écrit

chh := make(chan int, 2)

go func() {
    chh <- 1
    fmt.Printf("chh after 1: %v, %v\n", cap(chh), len(chh))
    chh <- 2
    fmt.Printf("chh after 2: %v, %v\n", cap(chh), len(chh))
    chh <- 3
    fmt.Printf("chh after 3: %v, %v\n", cap(chh), len(chh))
}()

fmt.Println(<-chh)
fmt.Println(<-chh)
fmt.Println(<-chh)

Le résultat de l'exécution est

1
chh after 1: 2, 0
chh after 2: 2, 0
chh after 3: 2, 1
2
3

C'est encore plus déroutant. Cette fois, c'est un autre goroutine qui effectue l'envoi. Je m'attends à ce qu'il soit bloqué immédiatement après le premier fmt.Println(<-chh) 期间,主 goroutine 应该被阻塞。调度程序将选择运行匿名函数的 goroutine,并且它应该执行到 chh <- 2,然后它会阻塞自身,调度程序再次恢复到主 goroutine。然而,如结果所示,第二个 goroutine 在 chh <- 1. Pourquoi cela arrive-t-il?

Edit : Je ne comprends toujours pas pourquoi mon local imprime 1 en premier lieu. Lorsque j'essaie d'utiliser go Playground sur le serveur distant, il affiche un comportement différent, désormais conforme à mes attentes.

On sait que le canal est composé de 3 files d'attente (réception des goroutines, envoi des goroutines et tampon de valeurs). Lorsque la fonction anonyme s'exécute, le canal chh的状态为(sending:empty,valuebuffer:empty,receiving:[main] ).

Le Goroutine enfant en cours d'exécution pousse simplement la valeur directement dans le Goroutine principal sans réellement la transmettre au tampon de valeur. C'est pourquoi chh推送后1的长度是0.

Solution

Cette chaîne peut accueillir deux personnes. Deux envois peuvent réussir sans blocage. Le troisièmene peut pas. Les envois ne seront bloqués que si la chaîne est pleine avant l'envoi.

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer