最近在开发过程中遇到了几个goroutine通讯的问题,我以为这几个问题很是具备表明性,所以拿出来和你们分享一下。golang
开发过程中有遇到这样的一种状况,须要检查channel是否关闭,若是关闭则不进行相应操做,不然会panic等现象。在golang的select语法当中,default分支能够解决上述问题,请看以下例子:并发
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 } } } }
上述的方式能够在处理dchan
的数据的时候处理异常并再也不接受来自dchan的数据。code
可是咱们须要考虑一种状况,若是在doSomeThing(data)
的过程中,出现异常(4)
,那么不容许往dchan
发送数据,并将closechan
关闭。在(5)
关闭closechan
以后就不会再进入(1)
的default流程了。开发
但是这还有问题,那就是若是doSomeThing(data)
处理的过程中,新来了一个数据进入到了dchan
,那么将会在(1)
和(2)
处阻塞,当doSomeThing(data)
处理完以后,还会多处理一次异常状况,也就是说在(5)
处将会close(closechan)
两次,这样会致使panic: close of closed channel
,因此咱们须要在(5)
再写一个相应的default
处理逻辑:it
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 } } } } }
当咱们在使用bufferd-channel的时候,咱们可能须要检查当前的channel是否已经满了,由于咱们可能不但愿此时goroutine阻塞,因此能够采用以下的方式进行处理:class
cc := make(chan int, 1) cc <- data1 select { case cc <- data2: fmt.Println("data already en-channel") default: fmt.Println("cc was full") }
在研究并发map的时候,会考虑到一种shard-map的实现方式,在读取map中的值的时候,须要经过多个小map中获取完整的map值,能够利用channel实现fan-in:sed
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) }