1. 程式人生 > >Go 緩衝 channel 和 非緩衝 channel 的區別

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 實時消費就不會導致阻塞了