在Go中,通道缓冲区的大小比预期的多一个值。

huangapple go评论73阅读模式
英文:

Channel buffer taking one more value than expected in Go

问题

我以为在Go语言中,通道默认情况下只能容纳一个值,除非指定了缓冲区大小。我在这里阅读到了这个问题的解答。但是当我运行以下代码时:

func main() {
    for i := range numGen(6) {
        log.Println("taking from channel", i)
    }
}

func numGen(num int) chan int {
    c := make(chan string)
    go func() {
        for i := 0; i < num; i++ {
            log.Println("passing to channel", i)
            c <- i
        }
        close(c)
    }()
    return c
}

我的输出是:

2017/06/13 18:09:08 passing to channel 0
2017/06/13 18:09:08 passing to channel 1
2017/06/13 18:09:08 taking from channel 0
2017/06/13 18:09:08 taking from channel 1
2017/06/13 18:09:08 passing to channel 2
2017/06/13 18:09:08 passing to channel 3
2017/06/13 18:09:08 taking from channel 2
2017/06/13 18:09:08 taking from channel 3
2017/06/13 18:09:08 passing to channel 4
2017/06/13 18:09:08 passing to channel 5
2017/06/13 18:09:08 taking from channel 4
2017/06/13 18:09:08 taking from channel 5

这表明该通道同时容纳了两个值。指定缓冲区大小如下所示:

c := make(chan int, 0)

没有起到任何作用。有没有办法让它只容纳一个值,而不是两个?

英文:

I thought that channels in Go only hold 1 value by default unless the buffer size if specified. I read that <a href="https://stackoverflow.com/questions/11943841/golang-what-is-channel-buffer-size">here</a>. But when I run this:

func main (){
    for i := range numGen(6) {
        log.Println(&quot;taking from channel&quot;, i)
    }
}

func numGen(num int) chan int {
    c := make(chan string)
    go func() {
        for i := 0; i &lt; num; i++ {
            log.Println(&quot;passing to channel&quot;, i)
            c &lt;- i
        }
        close(c)
    }
    return c
}

my output is:

2017/06/13 18:09:08 passing to channel 0
2017/06/13 18:09:08 passing to channel 1
2017/06/13 18:09:08 taking from channel 0
2017/06/13 18:09:08 taking from channel 1
2017/06/13 18:09:08 passing to channel 2
2017/06/13 18:09:08 passing to channel 3
2017/06/13 18:09:08 taking from channel 2
2017/06/13 18:09:08 taking from channel 3
2017/06/13 18:09:08 passing to channel 4
2017/06/13 18:09:08 passing to channel 5
2017/06/13 18:09:08 taking from channel 4
2017/06/13 18:09:08 taking from channel 5

which shows that the channel is holding 2 values at a time. Specifying a buffer size like this

c := make(chan int, 0)

does nothing. Any way I could make it only hold 1, value, not 2?

答案1

得分: 3

这是代码的执行过程:

  1. 主 goroutine 在通道上进行读取并阻塞。
  2. 第二个 goroutine 写入通道并继续执行。
  3. 第二个 goroutine 在第二次写入尝试时阻塞,因为没有人在读取。
  4. 主 goroutine 继续执行,打印读取的数字。
  5. 主 goroutine 读取另一个数字,因为有人在写入。
  6. 主 goroutine 打印读取的数字,并在下一次读取时阻塞。
  7. 第二个 goroutine 在步骤 2 处继续执行。

没有缓冲区,只有并发执行。

英文:

> which shows that the channel is holding 2 values at a time.

Thats not the case. This is how the code executes:

  1. The main goroutine blocks on a read on the channel
  2. The second goroutine writes to the channel and continues executing.
  3. The second goroutine blocks at the second write attempt because noone is reading
  4. The main goroutine continues executing, prints the read number
  5. The main goroutine reads another number since someone is writing to it
  6. The main goroutine prints the read number and blocks on the next read
  7. The second goroutine continues executing at step 2.

There is no buffer, just concurrency.

答案2

得分: 0

package main

import (
    "log"
)

func main() {
    seq := make(chan bool)
    for i := range numGen(6, seq) {
        <-seq
        log.Println("从通道中取出", i)
    }
}

func numGen(num int, seq chan bool) chan int {
    c := make(chan int)
    go func() {
        for i := 0; i < num; i++ {
            c <- i
            log.Println("向通道中传递", i)
            seq <- true // 为了保证顺序,这里发送一个信号。
        }
        close(c)
    }()

    return c
}

这是一个Go语言的代码示例,它创建了一个通道(channel)并使用goroutine来生成一系列数字。在主函数中,通过循环从通道中接收数字,并在接收完后发送一个信号量到另一个通道。在numGen函数中,使用循环将数字发送到通道中,并在发送完后发送一个信号量到seq通道。最后,关闭通道c。

请注意,我只翻译了代码部分,其他内容不做翻译。

英文:
package main

import (
    &quot;log&quot;
)

func main() {
    seq := make(chan bool)
    for i := range numGen(6, seq) {
        &lt;-seq
        log.Println(&quot;taking from channel&quot;, i)
    }
}

func numGen(num int, seq chan bool) chan int {
    c := make(chan int)
    go func() {
        for i := 0; i &lt; num; i++ {
            c &lt;- i
            log.Println(&quot;passing to channel&quot;, i)
            seq &lt;- true // 要保证顺序,这里发送一个信号量。
        }
        close(c)
    }()

    return c
}

huangapple
  • 本文由 发表于 2017年6月14日 07:18:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/44533029.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定