Goroutines channels and "stopping short"

Issue

I’m reading/working through Go Concurrency Patterns: Pipelines and cancellation, but i’m having trouble understanding the Stopping short section. We have the following functions:

func sq(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- n * n
        }
        close(out)
    }()
    return out
}

func gen(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        for _, n := range nums {
            out <- n
        }
        close(out)
    }()
    return out
}
func merge(cs ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    out := make(chan int, 1) // enough space for the unread inputs

    // Start an output goroutine for each input channel in cs.  output
    // copies values from c to out until c is closed, then calls wg.Done.
    output := func(c <-chan int) {
        for n := range c {
            out <- n
        }
        wg.Done()
    }
    wg.Add(len(cs))
    for _, c := range cs {
        go output(c)
    }

    // Start a goroutine to close out once all the output goroutines are
    // done.  This must start after the wg.Add call.
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

func main() {
    in := gen(2, 3)

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

    // Consume the first value from output.
    out := merge(c1, c2)
    fmt.Println(<-out) // 4 or 9
    return
    // Apparently if we had not set the merge out buffer size to 1
    // then we would have a hanging go routine. 
}

Now, if you notice line 2 in merge, it says we make the out chan with buffer size 1, because this is enough space for the unread inputs. However, I’m almost positive that we should allocate a chan with buffer size 2. In accordance with this code sample:

c := make(chan int, 2) // buffer size 2
c <- 1  // succeeds immediately
c <- 2  // succeeds immediately
c <- 3  // blocks until another goroutine does <-c and receives 1 

Because this section implies that a chan of buffer size 3 would not block. Can anyone please clarify/assist my understanding?

Solution

The program sends two values to the channel out and reads one value from the channel out. One of the values is not received.

If the channel is unbuffered (capacity 0), then one of the sending goroutines will block until the program exits. This is a leak.

If the channel is created with a capacity of 1, then both goroutines can send to the channel and exit. The first value sent to the channel is received by main. The second value remains in the channel.

If the main function does not receive a value from the channel out, then a channel of capacity 2 is required to prevent the goroutines from blocking indefinitely.

Answered By – Bayta Darell

Answer Checked By – Senaida (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.