doushi9780 2016-01-21 18:03
浏览 27
已采纳

去教程选择语句

I'm working through the examples at tour.golang.org, and I've encountered this code I don't really understand:

package main
import "fmt"

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

func main() {
    c := make(chan int)
    quit := make(chan int)
    go func() { // when does this get called?
        for i := 0; i < 10; i++ {
            fmt.Println(<-c)
        }
        quit <- 0
    }()
    fibonacci(c, quit)
}

I understand the basics of how channels work, but what I don't get is how the above select statement works. The explanation on the tutorial says:

"The select statement lets a goroutine wait on multiple communication operations. A select blocks until one of its cases can run, then it executes that case. It chooses one at random if multiple are ready."

But how are the cases getting executed? From what I can tell, they're saying:

case: send x to channel c

case: receive from quit

I think I understand that the second one executes only if quit has a value, which is done later inside the go func(). But what is the first case checking for? Also, inside the go func(), we're apparently printing values from c, but c shouldn't have anything in it at that point? The only explanation I can think of is that the go func() somehow executes after the call to fibonacci(). I'm guessing it's a goroutine which I don't fully understand either, it just seems like magic.

I'd appreciate if someone could go through this code and tell me what it's doing.

  • 写回答

3条回答 默认 最新

  • douzhuan4406 2016-01-21 18:12
    关注

    Remember that channels will block, so the select statement reads:

    select {
    case c <- x: // if I can send to c
        // update my variables
        x, y = y, x+y
    case <-quit: // If I can receive from quit then I'm supposed to exit
        fmt.Println("quit")
        return
    }
    

    The absence of a default case means "If I can't send to c and I can't read from quit, block until I can."

    Then in your main process you spin off another function that reads from c to print the results

    for i:=0; i<10; i++ {
        fmt.Println(<-c)  // read in from c
    }
    quit <- 0  // send to quit to kill the main process.
    

    The key here is to remember that channels block, and you're using two unbuffered channels. Using go to spin off the second function lets you consume from c so fibonacci will continue.


    Goroutines are so-called "green threads." Starting a function call with the keyword go spins it off into a new process that runs independent of the main line of execution. In essence, main() and go func() ... are running simultaneously! This is important since we're using a producer/consumer pattern in this code.

    fibonacci produces values and sends them to c, and the anonymous goroutine that's spawned from main consumes values from c and processes them (in this case, "processing them" just means printing to the screen). We can't simply produce all the values and then consume them, because c will block. Furthermore fibonacci will produce more values forever (or until integer overflow anyway) so even if you had a magic channel that had an infinitely long buffer, it would never get to the consumer.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥17 pro*C预编译“闪回查询”报错SCN不能识别
  • ¥15 微信会员卡接入微信支付商户号收款
  • ¥15 如何获取烟草零售终端数据
  • ¥15 数学建模招标中位数问题
  • ¥15 phython路径名过长报错 不知道什么问题
  • ¥15 深度学习中模型转换该怎么实现
  • ¥15 HLs设计手写数字识别程序编译通不过
  • ¥15 Stata外部命令安装问题求帮助!
  • ¥15 从键盘随机输入A-H中的一串字符串,用七段数码管方法进行绘制。提交代码及运行截图。
  • ¥15 TYPCE母转母,插入认方向