理解Go中通道执行顺序

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

Understanding order of channel execution in Go

问题

我正在研究Rob Pike在2012年Google I/O上介绍的《Go并发模式》幻灯片,并且其中一个关于顺序的示例有点令人困惑。在第29张幻灯片上,有一个示例展示了如何在多路复用后恢复顺序。简而言之,来自多个通道的消息被多路复用到一个单一的通道中,每个Message结构共享一个名为"waitForIt"的通道。这个通道的目的是确保提供消息的服务(在参考示例中是_boring_服务)和服务的客户端按顺序执行。我不明白为什么为了实现A-B-A-B-A-B的顺序,客户端必须通过waitForIt通道发送__2__个等待信号:

FIG1

for i := 0; i < 10; i++ {
    msg1 := <-c
    fmt.Printf("%s\n", msg1.str)
    msg2 := <-c
    fmt.Printf("%s\n", msg2.str)
    msg1.wait <- true
    msg2.wait <- true  /* 为什么需要第二个等待信号? */
}

如果Message结构共享同一个通道,为什么需要两个等待信号?难道一个单独的_<-wait_不足够吗,即:

FIG2

for i := 0; i < 10; i++ {
    msg1 := <-c
    fmt.Printf("%s\n", msg1.str)
    msg2 := <-c
    fmt.Printf("%s\n", msg2.str)
    msg1.wait <- true
}

然而,当只使用一个等待信号时,输出的开头会重复两次Message 1,然后顺序A-B-A-B...开始,输出如下:

Message 1: Iteration 0
Message 2: Iteration 0
Message 1: Iteration 1 // Message 1重复两次
Message 1: Iteration 2 // 这里是重复的地方
Message 2: Iteration 1
Message 1: Iteration 3
Message 2: Iteration 2
Message 1: Iteration 4
Message 2: Iteration 3
Message 1: Iteration 5

当在__FIG1__中有两个对_wait_变量的发送时,从一开始就是A-B-A-B...的顺序:

Message 1: Iteration 0
Message 2: Iteration 0
Message 1: Iteration 1
Message 2: Iteration 1
Message 1: Iteration 2
Message 2: Iteration 2
Message 1: Iteration 3
Message 2: Iteration 3
Message 1: Iteration 4
Message 2: Iteration 4

为什么在同一个通道上需要第二次对_wait_的发送才能得到正确的顺序?

英文:

Note: In this question I compare two versions of code and try to understand why they produce different output. Links to running examples of the two versions on play.golang.org are FIG1 and FIG2.


I'm working through the Go Concurrency Patterns slides that Rob Pike presented at Google I/O 2012 and the example on Sequencing is a bit confusing. On Slide 29 there's an example of how to restore sequencing after multiplexing. In short, messages from multiple channels are multiplexed into a single channel and each Message structure shares a channel called "waitForIt". This channel is meant to ensure that the service that provides the messages (in the referenced example the boring service) and the client of the service are in sequence. I don't understand why, in order to have a sequencing of A-B-A-B-A-B, the client must send 2 waits over the waitForIt channel:

FIG1

for i := 0; i &lt; 10; i++ {
	msg1 := &lt;-c
	fmt.Printf(&quot;%s\n&quot;, msg1.str)
	msg2 := &lt;-c
	fmt.Printf(&quot;%s\n&quot;, msg2.str)
	msg1.wait &lt;- true
	msg2.wait &lt;- true  /* why is this second wait necessary? */
}

Why are two waits necessary if the Message struct is sharing the same channel? Shouldn't a single <-wait be sufficient, i.e.

FIG2

for i := 0; i &lt; 10; i++ {
	msg1 := &lt;-c
	fmt.Printf(&quot;%s\n&quot;, msg1.str)
	msg2 := &lt;-c
	fmt.Printf(&quot;%s\n&quot;, msg2.str)
	msg1.wait &lt;- true
}

Yet when a single wait is used, Message 1 is repeated twice at beginning of the output and then the sequencing A-B-A-B... ensues, so that what's output is:

Message 1: Iteration 0
Message 2: Iteration 0
Message 1: Iteration 1 // Message 1 is repeated twice
Message 1: Iteration 2 // Here&#39;s the repetition
Message 2: Iteration 1
Message 1: Iteration 3
Message 2: Iteration 2
Message 1: Iteration 4
Message 2: Iteration 3
Message 1: Iteration 5

When there's two sends into the wait variable, as in FIG1, the sequencing is A-B-A-B... from the beginning:

Message 1: Iteration 0
Message 2: Iteration 0
Message 1: Iteration 1
Message 2: Iteration 1
Message 1: Iteration 2
Message 2: Iteration 2
Message 1: Iteration 3
Message 2: Iteration 3
Message 1: Iteration 4
Message 2: Iteration 4

Why is the second send into wait on the same channel required for a correct sequence?

答案1

得分: 2

阅读正确的示例[1],我猜你可能已经知道为什么需要同时使用"wait for it"。

以防万一:

你从通道中读取了两条消息。
每个消息生成器(在boring内部的goroutine)都在等待"wait for it"。
所以你需要发送两个"wait for it",否则其中一个将会一直等待。

如果你只通过通道发送一个"true",那么Joe会收到它的"wait for it"并可以发送一条新消息,但是Ann会一直等待(或者反过来)。

我猜在这一点上你的程序将会发生死锁。你想要读取两条消息,但是你只能接收到一条(来自Joe)。

我没有测试过,但我认为是这样。如果我错了,请告诉我。

[1] http://talks.golang.org/2012/concurrency/support/sequenceboring.go

英文:

Reading the proper example [1] I guess that you already may know why you need both "wait for it".

Just in case:

You read two messages from the channel.
Each message generator (goroutine inside boring) is waiting for a "wait for it".
So you need to send two "wait for it", otherwise one of them will keep waiting.

If you send only one "true" through the channel then Joe receives its "wait for it" and can send a new message but Ann keeps waiting(or reversed).

I guess that at this point your program will be deadlocked. You want to read two messages, but you can receive only one (from Joe).

I have not tested it but I think so. Let me know if I'm wrong.

[1] http://talks.golang.org/2012/concurrency/support/sequenceboring.go

答案2

得分: 1

上面的排序示例是不正确的。正确的示例可以在这里找到。

英文:

The sequencing examples above are incorrect. The correct examples can be found here.

huangapple
  • 本文由 发表于 2013年6月3日 02:42:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/16886048.html
匿名

发表评论

匿名网友

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

确定