请注意,本文为本作者原创。
please notice that this article is created by the author orginally.
In Golang, it is suggested that the writer is responsible for closing channel. for the simple example below:
package main
import (
"fmt"
"sync"
)
func worker(wg *sync.WaitGroup, ch chan int) {
defer wg.Done()
item := <-ch
fmt.Println(item)
}
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go worker(&wg, ch)
ch <- 1
close(ch)
wg.Wait()
}
But what will happen if the receiver routine continue to read data from channel that is closed? Let us see the example below:
package main
import (
"fmt"
"sync"
)
func worker(wg *sync.WaitGroup, ch chan int) {
defer wg.Done()
for {
item := <-ch
fmt.Println(item)
}
}
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go worker(&wg, ch)
ch <- 1
close(ch)
wg.Wait()
}
The code above is only added a for loop compared to the previous one. So what is the result? It will firstly print 1, followed by infinite 0s...
So why is it? When channel is closed, data value read by goroutine is zero value of the data type of channel.
So how to fix it to make it work as expected? Maybe we can check the read value to make the for loop exit in some condition?
package main
import (
"fmt"
"sync"
)
func worker(wg *sync.WaitGroup, ch chan int) {
defer wg.Done()
for {
item := <- ch
if item == 0 {
break
}
fmt.Println(item)
}
}
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go worker(&wg, ch)
ch <- 1
close(ch)
wg.Wait()
}
Although it can work as expected, but in the way of not elegant. We can use the for-range loop to make the code work without infinite loop and it seems to be more elegant. In this case, the for loop will exit normally when channel is closed. The code is as follows:
package main
import (
"fmt"
"sync"
)
func worker(wg *sync.WaitGroup, ch chan int) {
defer wg.Done()
for item := range ch {
fmt.Println(item)
}
}
func main() {
ch := make(chan int)
var wg sync.WaitGroup
wg.Add(1)
go worker(&wg, ch)
ch <- 1
close(ch)
wg.Wait()
}
The demonstration revealed that when working with channels, it is suggested to use for-range loop instead of usual for loop.
I hope this article can help you in some aspect, enjoy it~