你不知道的go channel

最近在开发过程中遇到了几个goroutine通讯的问题,我以为这几个问题很是具备表明性,所以拿出来和你们分享一下。golang

检查channel是否关闭

开发过程中有遇到这样的一种状况,须要检查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
                    }
                }   
        }
    }
}

检查buffered-channel是否已满

当咱们在使用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")
}

fan-in

在研究并发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)
}
相关文章
相关标签/搜索