簡體   English   中英

對“Go 中的並發”一書中描述的緩沖通道的不理解

[英]Incomprehension of buffered channels described in the "Concurrency in Go" book

我閱讀了 Katherine Cox-Buday 所寫的“Go 中的並發”一書,但我不理解緩沖通道示例的評論。

作者說:

if a goroutine making writes to a channel has knowledge of how many writes it will make,
it can be useful to create a buffered channel whose capacity is the number of writes to be made

聽起來很清楚,但例子令人困惑。

  1. 第一個示例 - 來源: https://github.com/kat-co/concurrency-in-go-src/blob/master/gos-concurrency-building-blocks/channels/fig-using-buffered-chans.go#L13
    var stdoutBuff bytes.Buffer         // <1>
    defer stdoutBuff.WriteTo(os.Stdout) // <2>

    intStream := make(chan int, 4) // <3>
    go func() {
        defer close(intStream)
        defer fmt.Fprintln(&stdoutBuff, "Producer Done.")
        for i := 0; i < 5; i++ {
            fmt.Fprintf(&stdoutBuff, "Sending: %d\n", i)
            intStream <- i
        }
    }()

    for integer := range intStream {
        fmt.Fprintf(&stdoutBuff, "Received %v.\n", integer)
    }

帶有注釋<3>的行有以下解釋:

Here we create a buffered channel with a capacity of one.

有 4 個,而不是 1 個。是不是搞錯了?

  1. 第二個示例 - 通道所有權,來源: https://github.com/kat-co/concurrency-in-go-src/blob/master/gos-concurrency-building-blocks/channels/fig-chan-ownership.go
    chanOwner := func() <-chan int {
        resultStream := make(chan int, 5) // <1>
        go func() {                       // <2>
            defer close(resultStream) // <3>
            for i := 0; i <= 5; i++ {
                resultStream <- i
            }
        }()
        return resultStream // <4>
    }

標記為<1>的行具有以下注釋:

Since we know we will produce six results, we create a buffered channel of five
so that the goroutine can complete as quickly as possible.

我完全不明白這個評論。 Goroutine 會被阻塞,因為通道有 5 條消息的容量,會產生 6 條消息,所以它會等到接收者收到第一條消息。

因為我們知道我們將產生六個結果,所以我們創建了一個 5 個緩沖通道,以便 goroutine 可以盡快完成。

你是正確的,goroutine 將阻塞直到收到一個值。

創建一個容量比要發送的值數量少一的通道是沒有意義的。 如果通道容量等於或大於值的數量,則可以消除 goroutine:

chanOwner := func() <-chan int {
    resultStream := make(chan int, 6)
    for i := 0; i < cap(resultStream); i++ {
        resultStream <- i
    }
    close(resultStream)
    return resultStream
}()

或者通過消除匿名 function 來實現:

    chanOwner := make(chan int, 6)
    for i := 0; i < cap(chanOwner); i++ {
        resultStream <- i
    }
    close(chanOwner)

是的,聽起來這本書需要一個更好的編輯器!


通道容量確實表示為make的第二個參數:

intStream := make(chan int, 4) // buffered-channel of capacity 4 (not 1!)

如果沒有在通道上進行讀取 - 那么寫入 goroutine 將寫入 5 次到緩沖通道(容量為 5)而沒有問題(即沒有阻塞)。 第 6 次寫入確實會阻塞 - 在緩沖區擁塞減少之前,goroutine 不會返回。

如果其他一些 goroutine 確實從通道中讀取了 - 甚至只是一次 - 然后緩沖區被釋放並且 writer goroutine 將能夠完成最終的寫入。

有 4 個,而不是 1 個。是不是搞錯了?

這似乎是一個錯字。 正如文檔中make指出的,第二個參數是通道容量:

通道:通道的緩沖區被初始化為指定的緩沖區容量 如果為零或省略大小,則通道是無緩沖的。

因此make(chan int, 4)是容量為 4 的 chan。

Goroutine 會被阻塞,因為通道有 5 條消息的容量,會產生 6 條消息,所以它會等到接收者收到第一條消息。

正確,聲明的 chan 容量為 5,如果沒有接收器,第六個也是最后一個發送操作確實會阻塞,因為通道緩沖區已滿。

假設各方都是善意的,這本書可能錯過了一輪校對。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM