This is a creation in Article, where the information may have evolved or changed.
Recently tried to write a program with go. Write a TCP Network service, run up will be all the CPU ran to 100%, slightly scary.
A simple analysis found the problem
package mainimport ( "runtime" "time")func main() { quit := make(chan bool) for i := 0; i != runtime.NumCPU(); i++ { go func() { for { select { case <-quit: break default: } } }() } time.Sleep(time.Second * 15) for i := 0; i != runtime.NumCPU(); i++ { quit <- true }}
The above code will fill all the CPUs, the reason is in select the usage.
In general, we select listen to each case IO event, each of which case is blocked. In the example above, we want select to exit the quit loop when we get the data inside the channel. In fact, each time select the loop will be executed to meet the conditions case , when quit there is no data in the channel, that is not satisfied with the case condition, it will jump directly to default , and then exit, select and the outside is a dead loop, so until the quit channel to read the data, Otherwise it will always run in a dead loop, even if it goroutine is running in one, it will fill up all the CPU.
The solution is also simple, default remove it, it will be blocked on the select quit channel IO, put this loop goroutine in, you can respond to the information in the channel at any time.
If it select is not in the loop, it can be added default , such as to determine whether a channel is full:
ch := make (chan int, 1)ch <- 1select {case ch <- 2:default: fmt.Println("channel is full !")}
Since ch the insertion of 1 is full, the statement is executed when the ch 2 is inserted and the discovery ch is full ( case 1 blocked) select default . This enables the detection to be channel full, rather than waiting.
Reference: Golang's Select typical usage