Heim  >  Artikel  >  Backend-Entwicklung  >  Der Blockierungsmechanismus des gepufferten Kanals von Go

Der Blockierungsmechanismus des gepufferten Kanals von Go

WBOY
WBOYnach vorne
2024-02-10 14:30:111026Durchsuche

Go 的 Buffered Channel 的阻塞机制

In der Go-Sprache gibt es einen speziellen Kanaltyp namens Buffered Channel, der eine bestimmte Anzahl von Elementen im Kanal speichert. Wenn die Anzahl der Elemente im Kanal die festgelegte Obergrenze erreicht, wird der Schreibvorgang blockiert, bis eine andere Coroutine Elemente aus dem Kanal liest. Wenn dagegen die Anzahl der Elemente im Kanal Null ist, wird der Lesevorgang ebenfalls blockiert, bis eine andere Coroutine Elemente in den Kanal schreibt. Dieser Blockierungsmechanismus kann die Synchronisation und Kommunikation zwischen Coroutinen effektiv steuern. In diesem Artikel stellen wir den Blockierungsmechanismus des Buffered Channel in der Go-Sprache im Detail vor.

Frageninhalt

In „Tour of Go“ wird der Beispielcode wie folgt angegeben:

package main

import "fmt"

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

Es lässt sich gut ausführen und ausdrucken

1
2

Dieses Verhalten weicht von der Beschreibung dieser Übung ab, in der es heißt:

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

in ch <- 2 行之后,ch is 已满,并且由于我们只运行 1 个单独的 Goroutine,即主 Goroutine,因此该 Goroutine 应该被阻塞,直到 ch is 被接收者消耗,因此代码不应该到达fmt.Println(<-ch) OK, sollte aber so etwas wie

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

Da dies jedoch nicht der Fall ist, bin ich verwirrt und suche nach Anleitung.

Dies ist ein weiterer Code, den ich geschrieben habe

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)

Das Ausführungsergebnis ist

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

Das ist noch verwirrender. Diesmal übernimmt eine andere Goroutine das Senden. Ich erwarte, dass es sofort nach dem ersten fmt.Println(<-chh) 期间,主 goroutine 应该被阻塞。调度程序将选择运行匿名函数的 goroutine,并且它应该执行到 chh <- 2,然后它会阻塞自身,调度程序再次恢复到主 goroutine。然而,如结果所示,第二个 goroutine 在 chh <- 1 blockiert wird. Warum passiert das?

Bearbeiten: Ich verstehe immer noch nicht, warum mein lokaler Drucker überhaupt 1 druckt. Wenn ich versuche, go Playground auf dem Remote-Server zu verwenden, zeigt es ein anderes Verhalten, das jetzt meinen Erwartungen entspricht.

Es ist bekannt, dass der Kanal aus 3 Warteschlangen besteht (Empfang von Goroutinen, Senden von Goroutinen und Wertpuffer). Wenn die anonyme Funktion ausgeführt wird, wird der Kanal chh的状态为(sending:empty,valuebuffer:empty,receiving:[main] ).

Die laufende untergeordnete Goroutine schiebt den Wert einfach direkt in die Haupt-Goroutine, ohne ihn tatsächlich an den Wertepuffer zu übergeben. Deshalb chh推送后1的长度是0.

Lösung

Dieser Kanal bietet Platz für zwei Personen. Zwei Versendungen können ohne Blockierung erfolgreich sein. Der Drittekann nicht. Sendungen werden nur blockiert, wenn der Kanal vor dem Senden voll ist.

Das obige ist der detaillierte Inhalt vonDer Blockierungsmechanismus des gepufferten Kanals von Go. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:stackoverflow.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen