What is happening in this go concurrency example?

Issue

I am on the concurrency example here: https://tour.golang.org/concurrency/5

This is the code:

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)
}

There is quite a bit about this that is confusing to me and the tour itself doesn’t say much about it. It says that select will wait on communication operations but I don’t really get how that applies to the function that it sends to a goroutine before calling fibonacci. fmt.Println is being sent the channel c, but I just don’t see why or how this makes any sense…

I have so many questions about this, I am hoping that everything falls into place after understanding the first part…

Solution

In the code example the goroutine is launched, and runs until it hits fmt.Println(<- c) where it is printing the values it receives from c. At this point in time i == 0 we’re in the first iteration. Meanwhile, since this is running in a goroutine, main has continued execution and called fibonacci passing it the c and quit channels. The fibonacci function is sitting in an ‘infinite’ select, meaning you will never get out of this without explicitly calling return as it does when it receives from the quit channel.

So back in main, where you invoked the goroutine, it blocks until receiving from the channel, fibonacci begins executing and sending on that channel, providing the next number in the fibonacci sequence until that loop terminates (when i == 10) at which point the code there moves down to quit <- 0 where is sends on the quit channel. Since you’re in an infinite select over there in fibonacci it will always execute the next available case, it cannot continue sending on c because that channel is not buffered, it only allows one item and is full, instead it moves in the quit case statement because it has received something on the quit channel, at which point it prints quit and returns.

Hope that helps. Some of the language may not be 100% accurate. Really just trying to illustrate how this control flow works. I think actually, the select waits until the goroutine in main can receive at which point it goes into the c <- x statement and sends. You can observe this by trying to read an item out of the channel after everything is done, which causes a panic. In effect they’re both waiting for one another, you can’t send on a full channel and if you just read off it without any other control flow (like a select) then you will block until there is something there to receive.

Answered By – evanmcdonnal

Answer Checked By – Robin (GoLangFix Admin)

Leave a Reply

Your email address will not be published.