首页 > 解决方案 > 对“Go 中的并发”一书中描述的缓冲通道的不理解

问题描述

我阅读了 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 条消息,所以它会等到接收者收到第一条消息。

标签: gochannel

解决方案


因为我们知道我们将产生六个结果,所以我们创建了一个 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
}()

或者通过消除匿名函数来实现:

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

推荐阅读