Golang:为什么增加缓冲通道的大小会导致我的 goroutine 输出消失?

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

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 (
	&quot;fmt&quot;
 	&quot;sync&quot;
)

var wg1, wg2 sync.WaitGroup

func main() {
    share := make(chan int, 10)
	out := make(chan string)
	go printChan(out)
	for j:= 1; j&lt;=7; j++ {
		go readInt(share, out, j)
	}
	for i:=1; i&lt;=100; i++ {
		share &lt;- 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 &lt;- fmt.Sprintf(&quot;goroutine:%d was sent %d&quot;, 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.

huangapple
  • 本文由 发表于 2015年9月12日 06:43:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/32533138.html
匿名

发表评论

匿名网友

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

确定