简体   繁体   中英

Why does my `for-select` statement keeps receiving from my channel even after I close it?

I have the following code:

package main

import (
    "fmt"
    "time"
)

func main() {
    ch := make(chan int)
    ch2 := make(chan int)
    go func(c chan int, c2 chan int) {
        for {
            select {
            case v := <-c:
                fmt.Println(v)
            case v := <-c2:
                fmt.Println(v)
            default:
            }
        }
    }(ch, ch2)
    ch <- 1
    close(ch)
    close(ch2)
    time.Sleep(10 * time.Second)
}

When I run this, it prints 1 to the stdout, and then keeps printing 0 . Why is this?

I know I can check whether the channel is closed in my goroutine, but I just want to know the reason for this.

Also, suppose I want to exit from a goroutine after all(multiple) channels are closed, is that possible? I was assuming that once all channels are closed, I could potentially exit from the goroutine in the default case after all channels are closed

That's the expected behavior per Spec: Receive operator:

A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.

See How does a non initialized channel behave?

If you want to terminate a loop once all values have been received from a channel (that were sent on it before it was closed), use the for... range construct, for example:

c := make(chan int) // Initialize some channel

for v := range c {
    fmt.Println("Received:", v)
}

If you have multiple channels and you want to receive from all, you may use multiple goroutines, each having a for range for a designated channel.

Another solution is:

A function can read from multiple inputs and proceed until all are closed by multiplexing the input channels onto a single channel that's closed when all the inputs are closed. This is called fan-in.

Read more about it in The Go Blog Go Concurrency Patterns: Pipelines and cancellation: Fan-out- fain-in .

The Go Programming Language Specificatio n

Close

After calling close, and after any previously sent values have been received, receive operations will return the zero value for the channel's type without blocking.

Receive operator

A receive operation on a closed channel can always proceed immediately, yielding the element type's zero value after any previously sent values have been received.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM