首頁  >  文章  >  後端開發  >  為什麼Go Channel的緩衝區不能正確限制寫入/讀取?

為什麼Go Channel的緩衝區不能正確限制寫入/讀取?

WBOY
WBOY轉載
2024-02-09 10:30:19423瀏覽

为什么Go Channel的缓冲区不能正确限制写入/读取?

php小編柚子在這篇文章中會回答一個常見問題:「為什麼Go Channel的緩衝區無法正確限制寫入/讀取?」在Go語言中,Channel是一種用於協程之間通訊的機制。當我們使用具有緩衝區的Channel時,期望能夠透過限制寫入或讀取操作的數量來控製程式的行為。然而,實際上,Channel的緩衝區並不能直接限制寫入/讀取操作的數量。以下將詳細闡述這個問題的原因和解決方案。

問題內容

我正在嘗試使用通道在兩個 go 例程之間進行通訊。首先,我創建了整數通道,然後將其作為參數傳遞給 go 例程,該例程列印從 0 到 10 的數字序列。這些程式的輸出沒有意義。

這是主要程式碼:

func worker(identifier string, ch chan<- int) {
    fmt.printf("entering worker %s\n", identifier)
    for i := 0; i < 10; i++ {
        fmt.printf("writing %d\n", i)
        ch <- i
    }

    fmt.printf("exiting worker %s\n", identifier)

    close(ch)
}

func main() {
    ch := make(chan int)
    go worker("1", ch)

    for v := range ch {
        fmt.printf("reading %d\n", v)
    }
}

對於該程式碼執行,我得到了以下輸出:

entering worker 1
writing 0
writing 1
reading 0
reading 1
writing 2
writing 3
reading 2
reading 3
writing 4
writing 5
reading 4
reading 5
writing 6
writing 7
reading 6
reading 7
writing 8
writing 9
reading 8
reading 9
exiting worker 1

請注意,有兩個寫入執行,然後是兩次讀取執行。

後來,我設定了一個緩衝區大小來實現以下功能:

func main() {
    ch := make(chan int, 3) // <= buffer
    go worker("1", ch)

    for v := range ch {
        fmt.printf("reading %d\n", v)
    }

}

然後,得到以下輸出:

Entering worker 1
Writing 0
Writing 1
Writing 2
Writing 3
Writing 4
Reading 0
Reading 1
Reading 2
Reading 3
Reading 4
Writing 5
Writing 6
Writing 7
Writing 8
Writing 9
Reading 5
Reading 6
Reading 7
Reading 8
Reading 9
Exiting worker 1

請注意,現在我們有 5 個寫入執行,然後有 5 個讀取執行。

一旦我們有了程式碼和輸出,最後一個問題就來了:為什麼這些執行的行為是這樣的?首先,它不是應該每次只讀取和寫入一個數字嗎?除此之外,為什麼第二次執行每次讀取和寫入 5 個數字而不是 3 個(因為這是緩衝區大小)?

解決方法

當列印訊息時以及何時從通道讀取或寫入數字時,您會混淆。

當寫入發生時,不會發生「寫入」訊息。它們發生在寫入之間的某個時刻。同樣,「正在閱讀」訊息發生在讀取之間的某個時刻。

這是安排第一個程式碼片段的一種方法,它會產生顯示的輸出:

  • 主要嘗試讀取,然後阻塞。
  • 工作人員列印「Writing 0」。
  • Worker 寫入 0,main 讀取。
  • 工人印出「Writing 1」。
  • 工作執行緒嘗試寫入 1,但被阻止。
  • 主要列印「Reading 0」。
  • 主要內容為 1。
  • 主要印刷品「閱讀1」。
  • 主要嘗試讀取,然後阻塞。

Control 像這樣在 main 和 Worker 之間不斷傳遞,每個在阻塞之前列印 2 個訊息。

同樣,您的第二個片段也可以這樣安排:

  • 主要嘗試讀取,然後阻塞。
  • Worker 列印“Writing 0”,並將 0 直接傳送到 main。
  • Worker 印出“Writing 1”,並緩衝 1。
  • Worker 印出“Writing 2”,並緩衝 2。
  • Worker 列印“Writing 3”,並緩衝 3。
  • 工作執行緒列印“Writing 4”,並阻止嘗試發送 4。
  • main 完成被阻塞的讀取,並印出「Reading 0」。
  • main 讀取緩衝的 1,並列印「Reading 1」。
  • main 讀取緩衝的 2,並列印「Reading 2」。
  • main 讀取緩衝的 3,並列印「Reading 3」。
  • main 讀取 Worker 被阻塞的 4,並印出「Reading 4」。
  • 主要嘗試讀取,然後阻塞。
  • 執行返回 Worker...

以上是為什麼Go Channel的緩衝區不能正確限制寫入/讀取?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

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