【问题标题】:What is happening in this go concurrency example?这个 go 并发示例中发生了什么?
【发布时间】:2016-10-12 04:23:05
【问题描述】:

我这里是并发示例:https://tour.golang.org/concurrency/5

这是代码:

package main

import "fmt"

func fibonacci(c, quit chan int) {
    x, y := 0, 1
    for {
        select {
        case c <- x:
            x, y = y, x + y
        case <- quit:
            fmt.Println("quit")
            return
        }
    }
}

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() {
        for i := 0; i < 10; i++ {
            fmt.Println(<- c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

这有很多让我感到困惑的地方,而这次旅行本身并没有说太多。它说 select 将等待通信操作,但在调用 fibonacci 之前,我真的不明白它如何应用于它发送到 goroutine 的函数。 fmt.Println 正在发送到频道 c,但我只是不明白为什么或如何这样做......

我对此有很多疑问,我希望在理解第一部分后一切都到位......

【问题讨论】:

    标签: go channel goroutine


    【解决方案1】:

    在代码示例中,goroutine 被启动,并运行直到它到达fmt.Println(&lt;- c),它正在打印从c 接收到的值。在这个时间点i == 0 我们处于第一次迭代中。同时,由于这是在 goroutine 中运行的,因此 main 继续执行并调用 fibonacci 并将 cquit 通道传递给它。 fibonacci 函数位于“无限”选择中,这意味着如果不显式调用 return,就像它从 quit 通道接收时所做的那样,您将永远无法摆脱这种状态。

    所以回到你调用 goroutine 的 main 中,它阻塞直到从通道接收,fibonacci 开始在该通道上执行和发送,提供fibonacci 序列中的下一个数字,直到该循环终止(当 @ 987654332@),此时代码向下移动到quit &lt;- 0,在退出通道上发送。由于您在fibonacci 中处于无限选择状态,它将始终执行下一个可用案例,它无法继续在c 上发送,因为该通道没有缓冲,它只允许一个项目并且已满,而是移动在quit case 语句中,因为它在quit 频道上收到了一些东西,此时它打印quit 并返回。

    希望对您有所帮助。有些语言可能不是 100% 准确的。真的只是想说明这个控制流是如何工作的。我认为实际上,选择会等到 main 中的 goroutine 可以接收,此时它会进入 c &lt;- x 语句并发送。您可以通过在所有操作完成后尝试从频道中读取项目来观察这一点,这会导致恐慌。实际上他们都在等待对方,你不能在一个完整的频道上发送,如果你只是在没有任何其他控制流(如选择)的情况下读取它,那么你将阻塞直到有东西可以接收。

    【讨论】:

    • 感谢您的回答,这对第一部分有所帮助,但现在我对 select 语句感到困惑,是否选择 c &lt;- x 部分是因为 goroutine “打开”通道然后切换声明类似于if x can send to c; do...?如果我是正确的,那么我该如何解释第二种情况......?
    • @deltaskelta 是的,这就是基本思想。把它想象成一个开关,它执行第一个满足的条件。你是从quit 频道接收的,所以在quit 上发送的东西会让你处于这种情况,你在c 上发送,所以已经读过c 的东西会打开它以进行另一次写入,导致你进入那个案例。
    猜你喜欢
    • 2014-04-17
    • 1970-01-01
    • 1970-01-01
    • 2021-02-18
    • 1970-01-01
    • 1970-01-01
    • 2019-01-13
    • 1970-01-01
    相关资源
    最近更新 更多