Go Channel 高級實踐

  1. 本文主要講實踐,原理部分會一筆帶過,關於 go 語言併發實現和內存模型後續會有文章。
  2. channel 實現的源碼不復雜,推薦閱讀,https://github.com/golang/go/...

channel 是幹什麼的

意義:channel 是用來通訊的

實際上:(數據拷貝了一份,並經過 channel 傳遞,本質就是個隊列)html

channel 應該用在什麼地方

核心:須要通訊的地方

例如如下場景:git

  • 通知廣播
  • 交換數據
  • 顯式同步
  • 併發控制
  • ...

記住!channel 不是用來實現鎖機制的,雖然有些地方能夠用它來實現相似讀寫鎖,保護臨界區的功能,但不要這麼用!github

channel 用例實現

超時控制

// 利用 time.After 實現
func main() {
    done := do()
    select {
    case <-done:
        // logic
    case <-time.After(3 * time.Second):
        // timeout
    }
}

func do() <-chan struct{} {
    done := make(chan struct{}, 1)
    go func() {
        // do something
        // ...
        done <- struct{}{}
    }()
    return done
}

取最快的結果

比較常見的一個場景是重試,第一個請求在指定超時時間內沒有返回結果,這時重試第二次,取兩次中最快返回的結果使用。
超時控制在上面有,下面代碼部分就簡單實現調用屢次了。golang

func main() {
    ret := make(chan string, 3)
    for i := 0; i < cap(ret); i++ {
        go call(ret)
    }
        fmt.Println(<-ret)
}

func call(ret chan<- string) {
    // do something
    // ...
    ret <- "result"
}

限制最大併發數

// 最大併發數爲 2
limits := make(chan struct{}, 2)
for i := 0; i < 10; i++ {
    go func() {
        // 緩衝區滿了就會阻塞在這
        limits <- struct{}{}
        do()
        <-limits
    }()
}

for...range 優先

for ... range c { do } 這種寫法至關於 if _, ok := <-c; ok { do }併發

func main() {
    c := make(chan int, 20)
    go func() {
        for i := 0; i < 10; i++ {
            c <- i
        }
        close(c)
    }()
    // 當 c 被關閉後,取完裏面的元素就會跳出循環
    for x := range c {
        fmt.Println(x)
    }
}

多個 goroutine 同步響應

利用 close 廣播app

func main() {
    c := make(chan struct{})
    for i := 0; i < 5; i++ {
        go do(c)
    }
    close(c)
}

func do(c <-chan struct{}) {
    // 會阻塞直到收到 close
    <-c
    fmt.Println("hello")
}

非阻塞的 select

select 自己是阻塞的,當全部分支都不知足就會一直阻塞,若是想不阻塞,那麼一個什麼都不幹的 default 分支是最好的選擇code

select {
case <-done:
    return
default:   
}

for{select{}} 終止

儘可能不要用 break label 形式,而是把終止循環的條件放到 for 條件裏來實現htm

for ok {
    select {
    case ch <- 0:
    case <-done:
        ok = false
    }
}

未完待續

...隊列

channel 特性

基礎特性

操做 值爲 nil 的 channel 被關閉的 channel 正常的 channel
close panic panic 成功關閉
c<- 永遠阻塞 panic 阻塞或成功發送
<-c 永遠阻塞 永遠不阻塞 阻塞或成功接收

happens-before 特性

  1. 無緩衝時,接收 happens-before 發送
  2. 任何狀況下,發送 happens-before 接收
  3. close happens-before 接收

參考

相關文章
相關標籤/搜索