func main() {
messages := make(chan string)
go func() { messages <- "hello" }()
go func() { messages <- "ping" }()
msg := <-messages
msg2 := <-messages
fmt.Println(msg)
fmt.Println(msg2)
以上代码始终打印&#34; ping&#34;然后&#34;你好&#34;在我的终端上。 我对这个打印的顺序很困惑,所以我想知道我是否可以对我的想法做一些澄清。
据我所知,在等待发送方和接收方时,无缓冲的通道都在阻塞。因此,在上述情况下,当执行这两个例程时,在两种情况下都没有接收器。所以我猜这两个例程都会阻塞,直到通道上的接收器可用。
现在......我会假设第一个&#34;你好&#34;尝试进入频道,但必须等待......同时,&#34; ping&#34;尝试,但又要等待。然后
msg := <- messages
出现了,所以我假设在那个阶段,程序将任意选择一个等待的goroutine并允许它将消息发送到通道,因为msg已准备好接收。
然而,似乎无论我运行多少次程序,总是被msg指定为&#34; ping&#34;和msg2被分配&#34;你好&#34;,这给人的印象是&#34; ping&#34;始终优先发送(至msg)。那是为什么?
答案 0 :(得分:5)
这不是关于阅读频道的顺序,而是关于无法保证的goroutines执行的顺序。
尝试从你写入频道的函数(写作前后)'打印',我认为它应该与从频道读取的顺序相同。
答案 1 :(得分:1)
Golang Spec Channels order被描述为: -
频道充当先进先出队列。例如,如果一个 goroutine在通道上发送值,第二个goroutine接收 他们,这些价值是按照发送的顺序收到的。
它将打印在另一端首先接收的值。
如果您想要同步它们,请使用不同的渠道或添加wait Groups
。
package main
import (
"fmt"
)
func main() {
messages1 := make(chan string)
messages2 := make(chan string)
go func(<-chan string) {
messages2 <- "ping"
}(messages2)
go func(<-chan string) {
messages1 <- "hello"
}(messages1)
fmt.Println(<-messages1)
fmt.Println(<-messages2)
}
如果您发现根据您的选择使用不同的渠道,您可以轻松获得任何您想要的价值。
答案 2 :(得分:0)
我只是经历了同样的事情。在这里查看我的信息:Golang channels, order of execution
像您一样,我看到了一种违反直觉的模式。在实际上不应该存在模式的地方。一旦启动执行流程,就启动了一个执行线程,并且基本上所有关于线程执行其步骤顺序的押注都在那一点上。但是如果要下订单,逻辑会告诉我们第一个被调用的命令将首先执行。
实际上,如果您每次都重新编译该程序,结果将有所不同。这就是我开始在本地计算机上编译/运行它时发现的。为了使结果随机,我不得不通过添加和删除空格来“弄脏”文件。然后,编译器将重新编译程序,然后得到执行的随机顺序。但是,在go沙箱中进行编译时,结果始终相同。
使用沙箱时,显然会缓存结果。通过使用微不足道的更改,我无法获得在沙箱中进行更改的命令。我更改它的唯一方法是在go语句的启动之间发出time.Sleep(1)命令。然后,第一个启动的将是每次执行的第一个。我仍然不认为我会继续下去,因为它们是独立的执行线程,并且没有保证。
最重要的是,我看到了确定性结果,应该没有确定性。那就是让我困扰的原因。当我发现结果在正常环境中确实是随机的时,我被彻底清除了。沙箱是一个很棒的工具。但这不是正常的环境。在本地编译并运行代码,您将看到预期的结果。
答案 3 :(得分:0)
当我第一次遇到这个时,我很困惑。但现在我对此很清楚。原因不是频道,而是goroutine。
正如The Go Memory Model所述,无法保证goroutine的运行和退出,因此,当您创建两个goroutine时,无法确保它们按顺序运行。
因此,如果要按照FIFO规则进行打印,则可以这样更改代码:
func main() {
messages := make(chan string)
go func() {
messages <- "hello"
messages <- "ping"
}()
//go func() { messages <- "ping" }()
msg := <-messages
msg2 := <-messages
fmt.Println(msg)
fmt.Println(msg2)
}