golang開發:channel使用

channel主要是用於多個goroutine之間通信

channel語法

channel是引用類型,需要實用make來創建channel,如下
make(chan Type, [buffer])
chan Type 通道的類型
buffer 是可選參數,代表通道緩衝區的大小(省略則代表無緩衝)
向channel裏面寫入數據使用 <- 符號

q := make(chan bool)
q<-true

從channel裏面讀取數據也是使用 <- 符號,只不過寫入的channel在右邊,讀取的時候channel在左邊。意思跟方向是一致的,一個是數據進入channel,一個是數據從channel出去

q := make(chan bool)
<-q

有緩衝channel的使用

我們一直使用的無緩衝的channel,今天主要學習下有緩存的channel。
無緩衝的channel,寫入數據後一定要有goroutine 從channel讀取數據後再寫入,否則程序會panic。

func main() {
	ch := make(chan int)
	ch<-1
}

fatal error: all goroutines are asleep - deadlock!

goroutine 1 [chan send]:

有緩衝的channel,可以寫入緩衝大小個數據,可以沒有goroutine從channel讀取。

func main() {
	ch := make(chan int,2)
	ch<-1
	ch<-2
}


Process finished with exit code 0

執行結果跟預期是一致的。

有緩衝大小的channel使用場景

假如我們有一個任務需要10個goroutine去調度執行,只要有一個goroutine執行完畢,調度就應該結束。我們看下僞代碼

func test(wg *sync.WaitGroup,ch chan int,i int) {
	fmt.Println("test code")
	ch<-i
}

func main() {
	fmt.Println("start",runtime.NumGoroutine())
	ch := make(chan int)
	wg := new(sync.WaitGroup)
	for i:=0;i<10;i++ {
		wg.Add(1)
		go test(wg,ch,i)
	}
	fmt.Println(<-ch)
	fmt.Println("end",runtime.NumGoroutine())
	wg.Done()
}

start 1
test code
9
end 10

從執行結果上看,是第9個goroutine首先執行完畢了。程序也正常退出了。但是我們看到,加上主goroutine,內存中一共有11個goroutine,程序退出的時候還有10個goroutine,減去一個主goroutine,還有9個goroutine沒有退出,這個對程序來說是不允許,可能會泄漏或者長期佔用資源不釋放。

但是我們如果使用了有緩衝的channel,就可以利用channel的緩衝機制正常退出全部的goroutine了。
看下代碼

func test(wg *sync.WaitGroup,ch chan int,i int) {
	ch<-i
}

func main() {
	fmt.Println("start",runtime.NumGoroutine())
	ch := make(chan int, 10)
	wg := new(sync.WaitGroup)
	for i:=0;i<10;i++ {
		wg.Add(1)
		go test(wg,ch,i)
	}
	fmt.Println(<-ch,"success")
	for i:= 0;i<9;i++ {
	 fmt.Println(<-ch)
	}
	fmt.Println("end",runtime.NumGoroutine())
	wg.Done()
}

start 1
0 success
1
2
4
3
5
6
7
8
9
end 1

Process finished with exit code 0

打印success的時候,第一個goroutine已經將任務完成,循環9次將channel裏面的數據讀取出來,保證創建的goroutine都不會阻塞能夠正常退出來。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章