英文:
Golang: Why does increasing the size of a buffered channel eliminate output from my goroutines?
问题
我正在尝试理解为什么将通道的缓冲区大小增大会导致代码运行出现意外情况。如果缓冲区小于我的输入(100个整数),则输出结果符合预期,即7个goroutine分别读取输入的子集并在另一个通道上发送输出,然后打印出来。如果缓冲区的大小与输入相同或更大,我将得不到任何输出和错误。我是不是在错误的时间关闭了通道?我对缓冲区的工作原理有错误的期望吗?还是其他原因?
以下是要翻译的代码:
package main
import (
"fmt"
"sync"
)
var wg1, wg2 sync.WaitGroup
func main() {
share := make(chan int, 10)
out := make(chan string)
go printChan(out)
for j := 1; j <= 7; j++ {
go readInt(share, out, j)
}
for i := 1; i <= 100; i++ {
share <- i
}
close(share)
wg1.Wait()
close(out)
wg2.Wait()
}
func readInt(in chan int, out chan string, id int) {
wg1.Add(1)
for n := range in {
out <- fmt.Sprintf("goroutine:%d was sent %d", id, n)
}
wg1.Done()
}
func printChan(out chan string) {
wg2.Add(1)
for l := range out {
fmt.Println(l)
}
wg2.Done()
}
要运行此代码:
小缓冲区,预期输出:http://play.golang.org/p/4r7rTGypPO
大缓冲区,无输出:http://play.golang.org/p/S-BDsw7Ctu
英文:
I am trying to understand why making the buffer size of a channel larger changes causes my code to run unexpectedly. If the buffer is smaller than my input (100 ints), the output is as expected, i.e., 7 goroutines each read a subset of the input and send output on another channel which prints it. If the buffer is the same size or larger than the input, I get no output and no error. Am I closing a channel at the wrong time? Do I have the wrong expectation about how buffers work? Or, something else?
package main
import (
"fmt"
"sync"
)
var wg1, wg2 sync.WaitGroup
func main() {
share := make(chan int, 10)
out := make(chan string)
go printChan(out)
for j:= 1; j<=7; j++ {
go readInt(share, out, j)
}
for i:=1; i<=100; i++ {
share <- i
}
close(share)
wg1.Wait()
close(out)
wg2.Wait()
}
func readInt(in chan int, out chan string, id int) {
wg1.Add(1)
for n := range in {
out <- fmt.Sprintf("goroutine:%d was sent %d", id, n)
}
wg1.Done()
}
func printChan(out chan string){
wg2.Add(1)
for l := range out {
fmt.Println(l)
}
wg2.Done()
}
To run this:
Small buffer, expected output. http://play.golang.org/p/4r7rTGypPO
Big buffer, no output. http://play.golang.org/p/S-BDsw7Ctu
答案1
得分: 4
这与缓冲区的大小无关。添加缓冲区只是暴露了一个bug,即在调用waitGroup.Add(1)
之前的位置。
在调度goroutine之前,必须先添加到WaitGroup
,否则可能会在waitGroup.Add(1)
执行之前调用Wait()
。
http://play.golang.org/p/YaDhc6n8_B
之所以第一个示例可以工作而第二个示例不行,是因为同步发送确保goroutine至少执行到那一步。在第二个示例中,for循环填满了通道,关闭了它,并在其他任何操作发生之前调用了Wait。
英文:
This has nothing directly to do with the size of the buffer. Adding the buffer is exposing a bug in where you're calling waitGroup.Add(1)
You have to add to the WaitGroup
before you dispatch the goroutine, otherwise you may end up calling Wait()
before the waitGroup.Add(1)
executes.
http://play.golang.org/p/YaDhc6n8_B
The reason it works in the first and not the second, is because the synchronous sends ensure that the gouroutines have executed at least that far. In the second example, the for loop fills up the channel, closes it and calls Wait before anything else can happen.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论