去频道:为什么两个不同的输出?

时间:2015-08-19 15:06:52

标签: 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。

为什么?

2 个答案:

答案 0 :(得分:4)

您的结果非常有意义。由于go例程彼此独立运行,你永远不会知道什么时候开始执行。一行

m[2] = "Second Value"

执行后会反映在你的主要例程上。

因此,当您在程序的第一次和第二次打印之间执行上面的行时,您会看到结果为

1-First Value
2-Second Value
3-Second Value
4-Second Value

如果不是,你会看到其他人。在第三次打印之前,确保完成其他的例程。

如果您修改程序有点像

,那就更清楚了
package main

import "fmt"
import "time"

func main() {
    m := make(map[int]string)
    m[2] = "First Value"
    c := make(chan bool)
    go func() {
        m[2] = "Second Value"
        c <- true
    }()
    time.Sleep(time.Second)
    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])
}

Playground

您很可能会得到以下输出

1-Second Value
2-Second Value
3-Second Value
4-Second Value

希望它有所帮助。

答案 1 :(得分:2)

您的代码实际上只确保第三个和第四个打印显示第二个值。当您将通道更改为缓冲区为1时,它并没有真正改变任何内容。

让我们看看第一个案例。您有一个无缓冲的频道。 您启动的go例程会更改地图的内容。但是您不知道调度程序何时运行它。这就是为什么有时你会看到一个结果而另一个时间看到另一个结果。 调用:_ = <-c将确保go例程已运行。因为这个调用会阻塞,直到go例程实际上在通道上写了一些东西。这就是为什么在最后两次打印中你永远不会看到“第一价值”的原因。

当你使用缓冲通道时,唯一会改变的是go例程将在写入通道后立即退出。没有别的(在Effective Go上阅读)。