我试图理解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。
为什么?
答案 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])
}
您很可能会得到以下输出
1-Second Value
2-Second Value
3-Second Value
4-Second Value
希望它有所帮助。
答案 1 :(得分:2)
您的代码实际上只确保第三个和第四个打印显示第二个值。当您将通道更改为缓冲区为1时,它并没有真正改变任何内容。
让我们看看第一个案例。您有一个无缓冲的频道。
您启动的go例程会更改地图的内容。但是您不知道调度程序何时运行它。这就是为什么有时你会看到一个结果而另一个时间看到另一个结果。
调用:_ = <-c
将确保go例程已运行。因为这个调用会阻塞,直到go例程实际上在通道上写了一些东西。这就是为什么在最后两次打印中你永远不会看到“第一价值”的原因。
当你使用缓冲通道时,唯一会改变的是go例程将在写入通道后立即退出。没有别的(在Effective Go上阅读)。