Preface
Recently, I used Go to develop back-end services. The service shutdown requires ensuring that the data in the channel has been read. The reason is very simple. After receiving the system interrupt signal, the system needs to finish the work to ensure that the data in the channel has to be processed before the system can be shut down. But it is not that simple to implement. Let’s take a look at the detailed introduction.
Criticisms about Go channel design and specification:
- There is no simple and common way to check if the channel is closed if it cannot be changed.
- Close the closed channel will cause panic, so it is dangerous to close the channel when the closer does not know whether the channel has been closed.
- Sending a value to a closed channel will result in panic, so it is dangerous if the sender (sender) sends a value to the channel without knowing whether the channel has been closed.
Therefore, the built-in close method of Golang can close the channel. If you send data to the closed channel, an error will be reported:panic: close of closed channel.
Look at the following code. For a period of time, the producer can continuously write data to the channel and the consumer processes it. After a period of time, the channel is closed. If there is still data sent to the channel, the program will report an error.
package main import ( "fmt" "sync" "time" ) func main() { jobs := make(chan int) var wg go func() { ( * 3) close(jobs) }() go func() { for i := 0; ; i++ { jobs <- i ("produce:", i) } }() (1) go func() { defer () for i := range jobs { ("consume:", i) } }() () }
The probability of errors occurring after several more runs is relatively high:
produce: 33334 consume: 33334 consume: 33335 produce: 33335 produce: 33336 consume: 33336 consume: 33337 produce: 33337 produce: 33338 consume: 33338 consume: 33339 produce: 33339 produce: 33340 consume: 33340 panic: send on closed channel goroutine 19 [running]: panic(0x49b660, 0xc042410bb0) C:/Go/src/runtime/:500 +0x1af .func2(0xc04203a180) C:/Users/tanteng/Go/src/examples/channel_close.go:18 +0x6b created by C:/Users/tanteng/Go/src/examples/channel_close.go:21 +0xb8 exit status 2
How to close the channel gracefully
So how do you determine whether the channel is closed before sending data to the channel?
1._,ok := <- jobs
At this time, if the channel is closed, the ok value is false. If the channel is not closed, a job will be missed.
2. Use the select method
Create another channel, called timeout. If the timeout is sent to this channel, send data to the channel of the jobs at the producer, listen to timeout with select, and close the channel of the jobs if the timeout is exceeded.
The complete code is as follows:
package main import ( "fmt" "sync" "time" ) func main() { jobs := make(chan int) timeout := make(chan bool) var wg go func() { ( * 3) timeout <- true }() go func() { for i := 0; ; i++ { select { case <-timeout: close(jobs) return default: jobs <- i ("produce:", i) } } }() (1) go func() { defer () for i := range jobs { ("consume:", i) } }() () }
This ensures that data will not be sent to the closed channel.
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.