Go 緩衝 channel 和 非緩衝 channel 的區別

在看本篇文章前我們需要了解阻塞的概念
  • 在執行過程中暫停,以等待某個條件的觸發 ,我們就稱之爲阻塞

在Go中我們make一個channel有兩種方式,分別是有緩衝的和沒緩衝的
  • 緩衝channelbuffer channel 創建方式爲 make(chan TYPE,SIZE)
    • make(chan int,3) 就是創建一個int類型,緩衝大小爲3channel
  • 非緩衝channelunbuffer channel 創建方式爲 make(chan TYPE)
    • make(chan int) 就是創建一個int類型的非緩衝channel

  • 非緩衝channel 和 緩衝channel 的區別
    • 非緩衝 channelchannel 發送和接收動作是同時發生的
    • 例如 ch := make(chan int) ,如果沒 goroutine 讀取接收者<-ch ,那麼發送者ch<- 就會一直阻塞
    • 緩衝 channel 類似一個隊列,只有隊列滿了纔可能發送阻塞

  • 代碼演示

  • 非緩衝 channel

package main

import (
	"fmt"
	"time"
)

func loop(ch chan int) {
	for {
		select {
		case i := <-ch:
			fmt.Println("this  value of unbuffer channel", i)
		}
	}
}

func main() {
	ch := make(chan int)
	ch <- 1
	go loop(ch)
	time.Sleep(1 * time.Millisecond)
}
  • 這裏會報錯 fatal error: all goroutines are asleep - deadlock! 就是因爲 ch<-1 發送了,但是同時沒有接收者,所以就發生了阻塞
  • 但如果我們把 ch <- 1 放到 go loop(ch) 下面,程序就會正常運行

  • 緩衝 channel 的阻塞只會發生在 channel 的緩衝使用完的情況下
package main

import (
	"fmt"
	"time"
)

func loop(ch chan int) {
	for {
		select {
		case i := <-ch:
			fmt.Println("this  value of unbuffer channel", i)
		}
	}
}

func main() {
	ch := make(chan int,3)
	ch <- 1
	ch <- 2
	ch <- 3
	ch <- 4
	go loop(ch)
	time.Sleep(1 * time.Millisecond)
}

  • 這裏也會報 fatal error: all goroutines are asleep - deadlock! ,這是因爲 channel 的大小爲 3 ,而我們要往裏面塞 4 個數據,所以就會阻塞住
  • 解決的辦法有兩個
    • channel 開大一點,這是最簡單的方法,也是最暴力的
    • channel 的信息發送者 ch <- 1 這些代碼移動到 go loop(ch) 下面 ,讓 channel 實時消費就不會導致阻塞了
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章