goconcurrencygoroutine

Goroutine inside function


I've read https://go.dev/blog/pipelines and there're two functions:

// move numbers into a channel 
func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}

// square those numbers take from "in" channel
func sq(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

and inside main function

    in := gen(2, 3)

    // Distribute the sq work across two goroutines that both read from in.
    c1 := sq(in)
    c2 := sq(in)

I thought that sq is just a normal function, so c1 must take all values from "in" channel and c2 is empty, but it was not.

So this mean a goroutine inside a function still can get out of that function scope and return to main routine to execute next command ?


Solution

  • You misunderstand the concept of goroutines here, you may want to look into A Tour of Go : Concurrency.

    As explained “The gen function starts a goroutine that sends the integers” and “The second stage, sq,” also starts a goroutine that “receives integers” and “emits the square of each received integer”. Both gen and sq create a (result) channel to which the internally scheduled goroutines send integers and return this channel immediately without waiting for the goroutines to run.

    So both gen and sq return immediately while the goroutines are only scheduled for execution, but not yet executed. (Note that this is the most likely execution order, nothing gives you any synchronization guarantees here)

    This is probably not the best stuff to learn Go, you should write synchronous code first. See also “producer–consumer queue” in “Rethinking Classical Concurrency Patterns”.

    Assume we would block before calling merge: Since all channels are unbuffered (“sends and receives block until the other side is ready”) after starting the “Fan-out, fan-in” example the goroutine started by gen eventually gets scheduled, sends two values and is then blocked trying to send the third value, while the goroutines started by sq get scheduled, received one value each and are now blocked by trying to send the square to their respective out channel.

    This so far has nothing to do with “scope”, The only thing that is captured by the goroutines scope is a channel variable.

    When you execute this example on a machine with enough CPU cores all goroutines run in parallel. Note that when you call merge and read the out channels fast enough the order could change.