为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

Go
森林海 2021-11-01 16:02:40
我正在尝试了解 Go 中的频道。这是一个代码示例:package mainimport "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 Value2-First Value3-Second Value4-Second Value但有时我得到(结果 2):1-First Value2-Second Value3-Second Value4-Second Value更改c := make(chan bool)为 后c := make(chan bool, 1),出现同样的情况:有时结果 1,有时结果 2。为什么?
查看完整描述

2 回答

?
心有法竹

TA贡献1866条经验 获得超5个赞

你的结果是完全合理的。由于 goroutine 相互独立运行,您永远不会知道 goroutine 何时开始执行。只要行


m[2] = "Second Value"

执行后,它将反映在您的主要 go 例程中。


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


1-First Value

2-Second Value

3-Second Value

4-Second Value

当它不是你看到另一个。在第三次打印之前,您确保其他 go 例程已完成。


如果你稍微修改你的程序,只是为了更清除它


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

希望能帮助到你。


查看完整回答
反对 回复 2021-11-01
?
慕慕森

TA贡献1856条经验 获得超17个赞

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

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

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


查看完整回答
反对 回复 2021-11-01
  • 2 回答
  • 0 关注
  • 209 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信