首頁  >  文章  >  後端開發  >  Go 的 Buffered Channel 的阻塞機制

Go 的 Buffered Channel 的阻塞機制

WBOY
WBOY轉載
2024-02-10 14:30:111024瀏覽

Go 的 Buffered Channel 的阻塞机制

在Go語言中,有一種特殊的通道類型叫做Buffered Channel(緩衝通道),它在通道中儲存一定數量的元素。當通道中的元素數量達到設定的上限時,寫入操作會被阻塞住,直到有其他協程從通道中讀取元素。相反,當通道中的元素數量為零時,讀取操作也會被阻塞住,直到有其他協程向通道中寫入元素。這種阻塞機制可以有效控制協程之間的同步和通訊。在本文中,我們將詳細介紹Go語言中Buffered Channel的阻塞機制。

問題內容

在《Tour of Go》中,範例程式碼是這樣給出的:

package main

import "fmt"

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

它執行良好並印出來

1
2

此行為與此練習的描述不同,其中指出:

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

ch <- 2 行之後,ch is 已滿,並且由於我們只運行1 個單獨的Goroutine,即主Goroutine,因此該Goroutine 應該被阻塞,直到ch is 被接收者消耗,因此程式碼不應該到達fmt.Println(<-ch) 行,但應該說類似

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

但是,由於情況並非如此,我很困惑,並尋求指導。

這是我寫的另一段程式碼

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)

執行結果為

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

這更令人困惑。這次有另一個 goroutine 進行發送。我的期望是,在第一個 fmt.Println(<-chh) 期間,主 goroutine 應該被阻塞。調度程序將選擇運行匿名函數的 goroutine,並且它應該執行到 chh <- 2,然後它會阻塞自身,調度程序再次恢復到主 goroutine。然而,如結果所示,第二個 goroutine 在 chh <- 1 之後立即被阻塞。為什麼會這樣呢?

編輯: 我仍然不明白為什麼我的本地首先打印 1 。當我在遠端伺服器上嘗試使用 go Playground 時,它顯示出不同的行為,現在與我的期望一致。

已知channel是由3個佇列組成(接收goroutines、發送goroutines ans value buffer),當匿名函式執行時,channel chh的狀態為(sending:empty,valuebuffer: empty,receiving:[main] )

正在運行的子 Goroutine 只是將值直接推入主 Goroutine,而沒有實際將其傳遞到值緩衝區。這就是為什麼chh推送後1的長度是0

解決方法

該通道可容納兩人。兩次發送可以成功而不會阻塞。 第三個不能。只有當通道在發送之前已滿時,發送才會阻塞。

以上是Go 的 Buffered Channel 的阻塞機制的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除