你不知道的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)
}
相關文章
相關標籤/搜索