Recently in the development process encountered several goroutine communication problems, I think these questions are very representative, so take out and share with you.
Check if channel is closed
In the development process encountered such a situation, you need to check whether the channel is closed, if closed do not do the corresponding operation, otherwise it will panic and so on. In Golang's select syntax, the default branch solves the above problem, see the following example:
closechan := make(chan int,0)dchan := make(chan int,0)select{ case <- closechan: fmt.Println("channel already closed.") return default: fmt.Println("channel not closed, do your things") dchan <- 1 //1} go func(){ for{ select{ case data := <- dchan: //2 err := doSomeThing(data) //3 if err != nil /* some thing wrong*/ { //4 close(closechan) //5 } } } }
The above method can dchan handle the data at the time of processing the exception and no longer accept data from Dchan.
But we need to consider a situation where, if there is an doSomeThing(data) exception in the process, (4) it is not allowed dchan to send data and will be closechan closed. The (5) closechan default process is no longer entered after it has been closed (1) .
However, there is a problem, that is, if doSomeThing(data) the process of processing, a new data into the dchan , then will be blocked in (1) and, (2) when doSomeThing(data) finished, will also deal with an abnormal situation, that is, the (5) place will close(closechan) be Two times, this will cause panic: close of closed channel , so we need to (5) write a corresponding default processing logic:
go func(){ for{ select{ case data := <- dchan: //2 err := doSomeThing(data) //3 if err != nil /* some thing wrong*/ { //4 select{ case <-closechan: //do nothing return default: close(closechan) //5 } } } }}
Check if the Buffered-channel is full
When we are using Bufferd-channel, we may need to check that the current channel is full because we may not want to goroutine at this time, so we can do this in the following way:
cc := make(chan int, 1)cc <- data1select { case cc <- data2: fmt.Println("data already en-channel") default: fmt.Println("cc was full")}
Fan-in
When studying the concurrency map, consider a SHARD-MAP implementation, when reading the values in the map, you need to get the complete map value through multiple small maps, you can use the channel to achieve fan-in:
func fanin (chans []chan int, out Chan int) {wg: = sync. waitgroup{} WG. ADD (Len (Chans)) for _, ch: = Range Chans {go func (ch Chan int) {for t: = Range ch { Out <-T} WG. Done ()} (CH)} WG. Wait () Close (out)}