This is a creation in Article, where the information may have evolved or changed.
#核心内容:
What happens if the closed channel is read again?
How to tell if the channel is closed?
What's the use of nil channel?
Take a look at the problematic code snippet (abstract refinement):
func TestReadFromClosedChan(t *testing.T) {asChan := func(vs ...int) <-chan int {c := make(chan int)go func() {for _, v := range vs {c <- vtime.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)}close(c)}()return c}merge := func(a, b <-chan int) <-chan int {c := make(chan int)go func() {for {select {case v := <-a:c <- vcase v := <-b:c <- v}}}()return c}a := asChan(1, 3, 5, 7)b := asChan(2, 4, 6, 8)c := merge(a, b)for v := range c {fmt.Println(v)}}
The goal is simply to merge the A and B two channel (s) into C, and then print all the elements in C through the range traversal.
**but!! * * A piece of code that looks so simple gets the results unexpectedly. Like this:
12345678000...#以及无数的0...
It looks like C has a number of meaningless 0 after merging AB. The reason is:
Closed channel can be read by the consumer, after reading meaningful data, will read a bunch of empty values. For example, the int type here is 0.
After understanding the problem, think of the first feeling is to judge 0, if found to receive a bunch of 0 to abandon it. But there are two problems:
- In fact, the data is still flowing in the pipeline, resulting in an empty loop that affects performance.
- There may be real meaningful null values in the business, and at this time 0 does not mean the pipe is closed.
Fortunately, go <-chan provides two return values for the operation:
item,ok <- chan
The second parameter is a description of the channel state, and False indicates that Channnel is closed. This allows us to control the reading of the channel through the state of the channel.
But even if the channel is read again, it will read 0, not elegant enough. This time can be solved by nil channel.
The idea is to set the closed channel to nil, while reading the first to determine whether the channel is nil. The code will not be written. Very simple to implement.
Golang to channel design, can only say that the function is powerful and convenient enough. It's easy to run into a hole like this.