这个go并发例子中发生了什么?

时间:2016-10-11 19:48:20

标签: go channel goroutine

我在这里的并发示例: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频道,但我不知道为什么或如何有意义......

我对此有很多疑问,我希望在了解完第一部分后,一切都会落实到位......

1 个答案:

答案 0 :(得分:3)

在代码示例中,goroutine已启动,并一直运行,直到它到达fmt.Println(<- c),并打印从c收到的值。在这个时间i == 0,我们在第一次迭代中。同时,由于这是在goroutine中运行的,因此main继续执行并调用fibonacci传递cquit个频道。 fibonacci功能位于“无限”状态。选择,这意味着如果没有明确地调用return,就像从quit频道收到时那样,你永远不会离开。

所以回到main,你调用goroutine,它阻塞直到从通道接收,fibonacci开始执行并在该通道上发送,提供fibonacci序列中的下一个数字,直到该循环终止(当i == 10时)此处的代码向下移动到quit <- 0,在退出通道上发送。由于您在fibonacci中进行了无限选择,因此它将始终执行下一个可用情况,它无法继续在c上发送,因为该频道未缓冲,它只允许一个项目和已填满,而是在quit案例陈述中移动,因为它已在quit频道收到某些内容,此时它会打印quit并返回。

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