在看本篇文章前我們需要了解阻塞的概念
- 在執行過程中暫停,以等待某個條件的觸發 ,我們就稱之爲阻塞
在Go中我們make一個channel有兩種方式,分別是有緩衝的和沒緩衝的
- 緩衝
channel
即buffer channel
創建方式爲make(chan TYPE,SIZE)
- 如
make(chan int,3)
就是創建一個int
類型,緩衝大小爲3
的channel
- 如
- 非緩衝
channel
即unbuffer channel
創建方式爲make(chan TYPE)
- 如
make(chan int)
就是創建一個int
類型的非緩衝channel
- 如
- 非緩衝
channel
和 緩衝channel
的區別- 非緩衝
channel
,channel
發送和接收動作是同時發生的 - 例如
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
實時消費就不會導致阻塞了
- 把