猿问

Go 通道:为什么有两个不同的输出?

我正在尝试了解 Go 中的频道。这是一个代码示例:


package main


import "fmt"


func main() {

    m := make(map[int]string)

    m[2] = "First Value"

    c := make(chan bool)

    go func() {

        m[2] = "Second Value"

        c <- true

    }()

    fmt.Printf("1-%s\n", m[2])

    fmt.Printf("2-%s\n", m[2])

    _ = <-c

    fmt.Printf("3-%s\n", m[2])

    fmt.Printf("4-%s\n", m[2])

}

有时上述代码的输出是(结果 1):


1-First Value

2-First Value

3-Second Value

4-Second Value

但有时我得到(结果 2):


1-First Value

2-Second Value

3-Second Value

4-Second Value

更改c := make(chan bool)为 后c := make(chan bool, 1),出现同样的情况:有时结果 1,有时结果 2。


为什么?


森林海
浏览 210回答 2
2回答

心有法竹

你的结果是完全合理的。由于 goroutine 相互独立运行,您永远不会知道 goroutine 何时开始执行。只要行m[2] = "Second Value"执行后,它将反映在您的主要 go 例程中。因此,当在程序的第一次和第二次打印之间执行上述行时,您会看到结果为1-First Value2-Second Value3-Second Value4-Second Value当它不是你看到另一个。在第三次打印之前,您确保其他 go 例程已完成。如果你稍微修改你的程序,只是为了更清除它package mainimport "fmt"import "time"func main() {&nbsp; &nbsp; m := make(map[int]string)&nbsp; &nbsp; m[2] = "First Value"&nbsp; &nbsp; c := make(chan bool)&nbsp; &nbsp; go func() {&nbsp; &nbsp; &nbsp; &nbsp; m[2] = "Second Value"&nbsp; &nbsp; &nbsp; &nbsp; c <- true&nbsp; &nbsp; }()&nbsp; &nbsp; time.Sleep(time.Second)&nbsp; &nbsp; fmt.Printf("1-%s\n", m[2])&nbsp; &nbsp; fmt.Printf("2-%s\n", m[2])&nbsp; &nbsp; _ = <-c&nbsp; &nbsp; fmt.Printf("3-%s\n", m[2])&nbsp; &nbsp; fmt.Printf("4-%s\n", m[2])}Playground您很可能会得到以下输出1-Second Value2-Second Value3-Second Value4-Second Value希望能帮助到你。

慕慕森

您的代码实际上只是确保第三次和第四次打印显示第二个值。当您将通道更改为缓冲区为 1 时,它并没有真正改变任何东西。那么我们来看第一种情况。您有一个无缓冲的频道。您触发的 go 例程会更改地图的内容。但是您不知道调度程序何时会运行它。这就是为什么有时您会看到一个结果,而有时会看到另一个结果。call:_ = <-c将确保 go 例程已经运行。因为这个调用会阻塞,直到 go 例程实际在通道上写了一些东西。这就是为什么您永远不会在最后 2 次打印中看到“第一个值”的原因。当您使用缓冲通道时,唯一会改变的是 go 例程将在写入通道后立即退出。没有别的(在Effective Go上阅读)。
随时随地看视频慕课网APP

相关分类

Go
我要回答