golang讀取關閉channel遇到的問題/如何優雅關閉channel

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

#核心內容:

  1. 已關閉的channel再次讀取會出現什麼現象?

  2. 如何判斷channel關閉?

  3. 什麼是nil channel有什麼用?

先看看出問題的程式碼片段(抽象精簡):

func TestReadFromClosedChan(t *testing.T) {asChan := func(vs ...int) <-chan int {c := make(chan int)go func() {for _, v := range vs {c <- vtime.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)}close(c)}()return c}merge := func(a, b <-chan int) <-chan int {c := make(chan int)go func() {for {select {case v := <-a:c <- vcase v := <-b:c <- v}}}()return c}a := asChan(1, 3, 5, 7)b := asChan(2, 4, 6, 8)c := merge(a, b)for v := range c {fmt.Println(v)}}

目的很簡單,就是把a和b兩個channel合并到c當中,再通過range遍曆把c裡的元素全部列印出來。

**BUT!!**看起來如此簡單的一段代碼得到的結果卻出乎意料。像這樣:

12345678000...#以及無數的0...

看起來c合并了ab之後還多了一批無意義的0。原因在於:

closed channel是可以被消費者繼續讀取的,在讀完了有意義的資料之後,將讀到一堆空值。比如這裡的int類型就是0。

瞭解這個問題之後,想到第一感覺是對0進行判斷,如果發現收到一堆0則將其拋棄。但是有兩個問題:

  1. 實際上資料還是在管道中流動,會造成空迴圈,影響效能。
  2. 業務上可能存在真實有意義的空值,這個時候0不代表管道關閉。

好在go為<-chan操作提供了兩個傳回值:

item,ok <- chan

其中第二個參數就是對channel狀態的描述,false表示channnel已經關閉。這就讓我們可以通過channel的狀態來控制對channel的讀取。

可是即便這樣再次對channel進行讀取還是會讀到0,不夠優雅。這個時候可以通過nil channel來解決。

思路就是把已關閉的channel置為nil,在讀取的時候則優先判斷channel是否為nil。代碼就不寫了。很簡單的實現。

golang對channel的設計,只能說功能強大方便不足吧。很容易就會碰上這樣的坑。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.