Go通道:多出来的一行的功能

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

Go channel : the function of one extra line

问题

我正在学习Go语言中的并发模式,不确定Point A的目的是什么?

代码来自:https://talks.golang.org/2012/concurrency.slide#30

有人可以解释一下吗?谢谢

type Message struct {
	str  string
	wait chan bool
}

func main() {
	c := fanIn(boring("Joe"), boring("Ann"))
	for i := 0; i < 5; i++ {
		msg1 := <-c
		fmt.Println(msg1.str)
		msg2 := <-c
		fmt.Println(msg2.str)
		msg1.wait <- true
		msg2.wait <- true
	}
	fmt.Println("You're both boring; I'm leaving.")
}

func fanIn(input1, input2 <-chan Message) <-chan Message {
	c := make(chan Message)
	go func() {
		for {
			c <- <-input1
		}
	}()
	go func() {
		for {
			c <- <-input2
		}
	}()
	return c
}

func boring(msg string) <-chan Message {
	waitForIt := make(chan bool)
	c := make(chan Message)
	go func() { // We launch the goroutine from inside the function.
		for i := 0; ; i++ {
			c <- Message{fmt.Sprintf("%s %d", msg, i), waitForIt}
			time.Sleep(time.Duration(rand.Intn(2e3)) * time.Millisecond)
			<-waitForIt                          // <-----------------Point A
		}
	}()
	return c // Return the channel to the caller.
}
英文:

I am learning Concurrency Pattern in Go, not sure about what is the purpose for Point A ?

Code is taken from: https://talks.golang.org/2012/concurrency.slide#30

Can anyone explain to me ? Thanks

type Message struct {
	str  string
	wait chan bool
}

func main() {
	c := fanIn(boring(&quot;Joe&quot;), boring(&quot;Ann&quot;))
	for i := 0; i &lt; 5; i++ {
		msg1 := &lt;-c
		fmt.Println(msg1.str)
		msg2 := &lt;-c
		fmt.Println(msg2.str)
		msg1.wait &lt;- true
		msg2.wait &lt;- true
	}
	fmt.Println(&quot;You&#39;re both boring; I&#39;m leaving.&quot;)
}

func fanIn(input1, input2 &lt;-chan Message) &lt;-chan Message {
	c := make(chan Message)
	go func() {
		for {
			c &lt;- &lt;-input1
		}
	}()
	go func() {
		for {
			c &lt;- &lt;-input2
		}
	}()
	return c
}

func boring(msg string) &lt;-chan Message { 
	waitForIt := make(chan bool)
	c := make(chan Message)
	go func() { // We launch the goroutine from inside the function.
		for i := 0; ; i++ {
			c &lt;- Message{fmt.Sprintf(&quot;%s %d&quot;, msg, i), waitForIt}
			time.Sleep(time.Duration(rand.Intn(2e3)) * time.Millisecond)
			&lt;-waitForIt                          // &lt;-----------------Point A
		}
	}()
	return c // Return the channel to the caller.
}

答案1

得分: 2

fanIn函数会创建两个goroutine,分别从第一个和第二个“boring”消息通道中读取。由于这两个goroutine中的任何一个都可能在运行(另一个可能在休眠或者也在运行),我们无法确定元素被写入到合并通道的顺序:

A A A A A \
            > A B B A A A B A B B
B B B B B /

请注意,结果序列没有特定的顺序。

可以通过注释掉“等待”通道来演示这一点:

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Joe 4
Joe 5
Ann 3
你们两个都很无聊,我要走了。

等待通道的存在是为了恢复顺序,就像你链接的幻灯片中所说的那样。我们希望得到这样的结果:

A A A A A \
            > A B A B A B A B A B
B B B B B /

请注意,现在Ann和Joe是依次交替说话

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Ann 3
Joe 4
Ann 4
你们两个都很无聊,我要走了。

这段代码的作者决定通过让通道在waitForIt上等待并在main中通知来同步对通道的写入。这种行为依赖于我们在mainfor循环中得到的前两个消息的顺序。如果它们不是按顺序的,我们将得到相反的序列。

也许我没有看到更多的绝对同步保证,也许作者并不关心序列的顺序,只要它是一个重复的序列。但是这段代码并不是一个特别好的并发和同步的示例。

英文:

fanIn spawns two goroutines reading from the first and second "boring" Message-channels. As either of both goroutine might be running (and the other one sleeping or running as well) we don't know the order in which the elements get written to the unifying channel:

A A A A A \
            &gt; A B B A A A B A B B
B B B B B /

Note that the resulting sequence has no particular order.

This can be demonstrated by commenting out the "waiting"-channels:

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Joe 4
Joe 5
Ann 3
You&#39;re both boring; I&#39;m leaving.

The waiting channel exists to restore sequence as the slides you linked say. We want this:

A A A A A \
            &gt; A B A B A B A B A B
B B B B B /

Note how Ann and Joe talk one after the other now:

Joe 0
Ann 0
Joe 1
Ann 1
Joe 2
Ann 2
Joe 3
Ann 3
Joe 4
Ann 4
You&#39;re both boring; I&#39;m leaving.

The author of this piece of code decided to synchronize the writes to the channels by letting them wait on waitForIt and notifying in main. This behavior relies on the first two messages we get in main's for-loop to be in order. If they are not we'd get the inverse sequence.

Maybe I'm failing to see any more absolute synchronization guarantees, maybe the author didn't care about the order of the sequence as long as its a repeating sequence, but this code does not strike me as a particularly good example of concurrency and synchronization.

答案2

得分: 1

整个演示可以在YouTube上找到。大约在8分钟左右,它会更接近你的问题。Rob Pike解释了一切,但(这也是tomwilde所说的)演示中的示例被缩小,只让观众看到最重要的东西。在演示的后面,"boring"将被替换为"interesting"。这将使Rob试图解释的内容更加清晰。

英文:

The whole presentation can be found on YouTube. Around 8 minutes it will get closer to your problem. Rob Pike explains everything, but (this is also what tomwilde said) the examples in presentation are shrinked to only let the audience see the most important stuff. Later on in the presentation, the "boring" will be replaced by "interesting". It will make it much more clear what Rob tries to explain.

答案3

得分: 0

由于wait通道每次只能包含一个元素,PointA只是确保没有人会通过阻塞goroutine继续执行。然后,他会按顺序“卸载”通道,允许例程继续执行。

英文:

Since the wait channel can contain only one element per time, PointA is just making sure that no one will go ahead by blocking the goroutine. He will then "unload" the channel in order, allowing the routine to continue

huangapple
  • 本文由 发表于 2014年9月30日 15:52:49
  • 转载请务必保留本文链接:https://go.coder-hub.com/26115537.html
匿名

发表评论

匿名网友

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

确定