channel[通道]是golang的一種重要特性,正是因?yàn)閏hannel的存在才使得golang不同于其它語(yǔ)言。channel使得并發(fā)編程變得簡(jiǎn)單容易有趣。
channel的概念和語(yǔ)法
一個(gè)channel可以理解為一個(gè)先進(jìn)先出的消息隊(duì)列。channel用來在協(xié)程[goroutine]之前傳遞數(shù)據(jù),準(zhǔn)確的說,是用來傳遞數(shù)據(jù)的所有權(quán)。一個(gè)設(shè)計(jì)良好的程序應(yīng)該確保同一時(shí)刻channel里面的數(shù)據(jù)只會(huì)被同一個(gè)協(xié)程擁有,這樣就可以避免并發(fā)帶來的數(shù)據(jù)不安全問題[data races]。
正文
channel主要是用于多個(gè)goroutine之間通信
channel語(yǔ)法
channel是引用類型,需要實(shí)用make來創(chuàng)建channel,如下
make(chan Type, [buffer])
chan Type 通道的類型
buffer 是可選參數(shù),代表通道緩沖區(qū)的大小(省略則代表無緩沖)
向channel里面寫入數(shù)據(jù)使用 - 符號(hào)
q := make(chan bool)
q-true
從channel里面讀取數(shù)據(jù)也是使用 - 符號(hào),只不過寫入的channel在右邊,讀取的時(shí)候channel在左邊。意思跟方向是一致的,一個(gè)是數(shù)據(jù)進(jìn)入channel,一個(gè)是數(shù)據(jù)從channel出去
有緩沖channel的使用
我們一直使用的無緩沖的channel,今天主要學(xué)習(xí)下有緩存的channel。
無緩沖的channel,寫入數(shù)據(jù)后一定要有g(shù)oroutine 從channel讀取數(shù)據(jù)后再寫入,否則程序會(huì)panic。
func main() {
ch := make(chan int)
ch-1
}
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
有緩沖的channel,可以寫入緩沖大小個(gè)數(shù)據(jù),可以沒有g(shù)oroutine從channel讀取。
func main() {
ch := make(chan int,2)
ch-1
ch-2
}
Process finished with exit code 0
執(zhí)行結(jié)果跟預(yù)期是一致的。
有緩沖大小的channel使用場(chǎng)景
假如我們有一個(gè)任務(wù)需要10個(gè)goroutine去調(diào)度執(zhí)行,只要有一個(gè)goroutine執(zhí)行完畢,調(diào)度就應(yīng)該結(jié)束。我們看下偽代碼
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;i10;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
從執(zhí)行結(jié)果上看,是第9個(gè)goroutine首先執(zhí)行完畢了。程序也正常退出了。但是我們看到,加上主goroutine,內(nèi)存中一共有11個(gè)goroutine,程序退出的時(shí)候還有10個(gè)goroutine,減去一個(gè)主goroutine,還有9個(gè)goroutine沒有退出,這個(gè)對(duì)程序來說是不允許,可能會(huì)泄漏或者長(zhǎng)期占用資源不釋放。
但是我們?nèi)绻褂昧擞芯彌_的channel,就可以利用channel的緩沖機(jī)制正常退出全部的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;i10;i++ {
wg.Add(1)
go test(wg,ch,i)
}
fmt.Println(-ch,"success")
for i:= 0;i9;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的時(shí)候,第一個(gè)goroutine已經(jīng)將任務(wù)完成,循環(huán)9次將channel里面的數(shù)據(jù)讀取出來,保證創(chuàng)建的goroutine都不會(huì)阻塞能夠正常退出來。
到此這篇關(guān)于golang開發(fā)中channel使用的文章就介紹到這了,更多相關(guān)golang channel使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- Golang實(shí)現(xiàn)Directional Channel(定向通道)
- Golang的select多路復(fù)用及channel使用操作
- 詳解Golang中Channel的用法
- 基于golang channel實(shí)現(xiàn)的輕量級(jí)異步任務(wù)分發(fā)器示例代碼
- golang中for循環(huán)遍歷channel時(shí)需要注意的問題詳解
- golang 函數(shù)返回chan類型的操作