猿问

这个选择在goroutine中是如何工作的?

我一直在关注go tour的例子,我不明白这是如何运作的 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)

}


这是如何运作的?


当我试图理解时。


package main

import "fmt"


func b(c,quit chan int) {

    c <-1

    c <-2

    c <-3

}


func main() {

    c := make(chan int)

    quit := make(chan int)

    go func() {

        for i := 0; i < 10; i++ {

            fmt.Println(<-c)

        }

        quit <- 0

    }()

    b(c,quit)

}

这有时会打印1,2有时打印1,2,3,为什么?


莫回无
浏览 91回答 2
2回答

波斯汪

为了更好地理解斐波那契的例子,让我们分析不同的部分。首先是匿名函数go func() {&nbsp; &nbsp; for i := 0; i < 10; i++ {&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println(<-c)&nbsp; &nbsp; }&nbsp; &nbsp; quit <- 0}()“go”关键字将启动一个新的 goroutine,所以现在我们有了 “main” goroutine,而这个,它们将同时运行。循环告诉我们,我们将执行此命令 10 次:fmt.Println(<-c)此调用将阻塞,直到我们从通道接收到整数并打印它。一旦这种情况发生10次,我们将发出信号,表明这个goroutine已经完成了。quit <- 0现在让我们回到主 goroutine,当另一个 goroutine 启动时,它调用了函数 “finbonacci”,没有 “go” 关键字,所以这个调用在这里被阻止。fibonacci(c, quit)现在让我们分析一下函数x, y := 0, 1for {&nbsp; &nbsp; select {&nbsp; &nbsp; case c <- x:&nbsp; &nbsp; &nbsp; &nbsp; x, y = y, x+y&nbsp; &nbsp; case <-quit:&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("quit")&nbsp; &nbsp; &nbsp; &nbsp; return&nbsp; &nbsp; }}我们开始一个无限循环,在每次迭代中,我们将尝试从选择中执行一个案例第一种情况将尝试将斐波那契的序列值无限期地发送到通道,在某个时候,一旦另一个goroutine到达语句,这种情况将被执行,值将被重新计算,循环的下一次迭代将发生。fmt.Println(<-c)case c <- x:&nbsp; &nbsp; &nbsp; &nbsp; x, y = y, x+y&nbsp;第二种情况还不能运行,因为没有人向“退出”通道发送任何内容。case <-quit:&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; fmt.Println("quit")&nbsp; &nbsp; &nbsp; &nbsp; return}经过 10 次迭代后,第一个 goroutine 将停止接收新值,因此第一个选择事例将无法运行case c <- x: // this will block after 10 times, nobody is reading&nbsp; &nbsp; &nbsp; &nbsp; x, y = y, x+y&nbsp;此时,“选择”中没有一个案例可以执行,主goroutine被“阻止”(从逻辑角度来看更像是暂停)。最后,在某个时候,第一个goroutine将发出信号,表明它已经完成了使用“退出”通道quit <- 0这允许执行第二个“选择”情况,这将打破无限循环并允许“斐波那契”函数返回,主函数将能够以干净的方式完成。希望这有助于您理解斐波那契的例子。现在,移动到你的代码,你不是在等待匿名的goroutine完成,事实上,它甚至没有完成。您的“b”方法正在发送“1,2,3”并立即返回。由于它是 main 函数的最后一部分,因此程序将终止。如果你只看到“1,2”有时是因为“fmt”。Println“语句太慢,程序在可以打印 3 之前终止。

天涯尽头无女友

首先,在 中,语句尝试选择以下两个操作中的第一个完成操作:func fibonacciselectc <- x<- quit它相当容易理解,它试图从一个名为的通道接收值(并忽略接收的值)。<- quitquitc <- x表示发送等于 x 的值(是 x 的副本)。这似乎是解锁,但在Go中,当没有接收器时,通过无缓冲通道发送(在Go tour中进行了解释)阻止。所以这里的意思是,等待接收器准备好接收值(或缓冲区中的空间,如果它是缓冲通道),这在这个代码中意味着,然后将值发送到接收器。fmt.Println(<-c)因此,每当评估时,此语句都会取消阻止(完成)。也就是说,循环的每次迭代。<-c对于您的代码,虽然所有值 , 、 保证通过通道发送(并接收),但返回并因此保留而不保证完成。123func bfunc mainfmt.Println(3)在Go中,当返回时,程序终止,未完成的goroutine没有机会完成其工作 - 因此有时它会打印并停止工作。func main3
随时随地看视频慕课网APP

相关分类

Go
我要回答