理解go與channel的關(guān)系
sync.WaitGroup
使用sync.WaitGroup等待一組并發(fā)操作完成。
var wg sync.WaitGrop
func hello(i int){
defer wg.Done()
fmt.Println("hello",i)
}
func main(){
for i:=0;i<10;i++{
wg.Add(1)
go hello(i)
}
wg.Wait() //在這里阻塞等待go結(jié)束
fmt.Println("hello world")
}
channel 管道
通道的作用是用于兩個(gè)協(xié)程之間的通信:
分類:
無(wú)緩沖channel木缝;
有緩沖channel我碟。
//整形無(wú)緩沖通道
unbuffered := make(chan int)
//整形有緩沖通道
buffered := make(chan int 10)
功能:
無(wú)緩存通常用于同步通信
有緩存通常用于異步通信
語(yǔ)法:
//整形無(wú)緩沖通道
unbuffered := make(chan int)
//整形有緩沖通道
buffered := make(chan int 10)
//無(wú)緩沖管道使用
ch1 := make(chan string) //初始化一個(gè)無(wú)緩沖字符串管道
ch1 <- "hello world" //發(fā)送數(shù)據(jù)到管道(在這里就阻塞了)
data :=<- ch1 //從管道接受數(shù)據(jù)
close(ch1) //關(guān)閉管道
//有緩沖管道使用
//情況1:讀取堵塞
ch1 := make(chan int,5) //大小為5的管道
ch1 <- 10 //發(fā)送數(shù)據(jù)到管道
ch1 <- 20 //發(fā)送數(shù)據(jù)到管道
data :=<- ch1 //從管道接受數(shù)據(jù)
data2 :=<-ch1 //從管道接受數(shù)據(jù)
data3 :=<- ch1
fmt.Printf("data: %v\n", data)
fmt.Printf("data2: %v\n", data2)
fmt.Printf("data3: %v\n", data3) //因?yàn)楣艿乐兄挥?個(gè)數(shù)據(jù)矫俺,讀取第三個(gè)時(shí)會(huì)阻塞
close(ch1)
//情況2:發(fā)送阻塞
ch1 := make(chan int,1) //大小為1的管道
ch1 <- 10 //發(fā)送數(shù)據(jù)到管道
ch1 <- 20 //發(fā)送第二個(gè)數(shù)據(jù)到管道時(shí)會(huì)阻塞掸冤,因?yàn)楣艿赖拇笮≈挥?
data :=<- ch1 //從管道接受數(shù)據(jù)
fmt.Printf("data: %v\n", data)
close(ch1)
//情況三:無(wú)阻塞
ch1 := make(chan int,5) //字符串管道
ch1 <- 10 //發(fā)送數(shù)據(jù)到管道
ch1 <- 20 //發(fā)送數(shù)據(jù)到管道
data :=<- ch1 //從管道接受數(shù)據(jù)
data2 :=<-ch1 //從管道接受數(shù)據(jù)
fmt.Printf("data: %v\n", data)
fmt.Printf("data2: %v\n", data2)
close(ch1)
goroutine與channel
for range從channel中取值
當(dāng)通道被關(guān)閉后稿湿,會(huì)在通道內(nèi)的所有值被接收完畢后會(huì)自動(dòng)退出循環(huán)。ps:如果沒(méi)有關(guān)閉通道會(huì)死鎖饺藤。
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func f1(ch chan int){
defer wg.Done()
for x:=range ch{ //不斷地從管道讀取數(shù)據(jù),直到管道被關(guān)閉舰始,如果管道沒(méi)有被關(guān)閉咽袜,會(huì)無(wú)法退出造成死鎖
fmt.Println(x)
}
}
func main() {
ch := make(chan int,10)
wg.Add(1)
go f1(ch)
for i:=0;i<11;i++ {
ch<-i
}
close(ch) //這里不關(guān)閉管道會(huì)死鎖
wg.Wait()
}
當(dāng)通道被關(guān)閉后询刹,依舊可以從通道中讀取數(shù)據(jù),如果通道中已經(jīng)沒(méi)有數(shù)據(jù)那么會(huì)讀到0值沐兰。
func main() {
ch := make(chan int,2)
ch<-10
ch<-20
close(ch)
//關(guān)閉管道后依然可以讀到管道內(nèi)的數(shù)據(jù)蔽挠,for range只會(huì)讀去管道存在的數(shù)據(jù)
for x:=range ch {
fmt.Printf("x: %v\n", x)
}
//關(guān)閉了管道依然可以讀,管道沒(méi)有數(shù)據(jù)了比原,就會(huì)讀到0值,ok==false
x杠巡,ok:=<-ch
fmt.Printf("x: %v\n", x)
fmt.Printf("ok: %v\n", ok)
}
select
select可以從多個(gè)通道接收值,使用它可以同時(shí)響應(yīng)多個(gè)通道的操作蚌铜。
每個(gè) case 分支會(huì)對(duì)應(yīng)一個(gè)通道的通信(接收或發(fā)送)過(guò)程嫩海。select 會(huì)一直等待,直到其中的某個(gè) case 的通信操作完成時(shí)造壮,就會(huì)執(zhí)行該 case 分支對(duì)應(yīng)的語(yǔ)句骂束。
select 具有以下特點(diǎn):
可處理一個(gè)或多個(gè) channel 的發(fā)送/接收操作。
如果多個(gè) case 同時(shí)滿足旨枯,select 會(huì)隨機(jī)選擇一個(gè)執(zhí)行混驰。
-
對(duì)于沒(méi)有 case 的 select 會(huì)一直阻塞皂贩,可用于阻塞 main 函數(shù)昆汹,防止退出满粗。
ch := make(chan int, 1) for i := 1; i <= 10; i++ { select { //select處理的是一個(gè)發(fā)送或者讀取操作,如下對(duì)同一個(gè)管道的兩個(gè)不同操作映皆。 case x := <-ch: fmt.Println(x) case ch <- i: } }
select用于處理異步IO操作總結(jié)
1.select 會(huì)監(jiān)聽(tīng)case語(yǔ)句中的讀寫操作捅彻,當(dāng)case中的channel讀寫操作為非阻塞狀態(tài),將會(huì)觸發(fā)相應(yīng)的動(dòng)作从隆。
2.如果有多個(gè)case可以執(zhí)行缭裆,select會(huì)隨機(jī)公平地選出一個(gè)執(zhí)行,其他不會(huì)執(zhí)行艾杏。
3.如果沒(méi)有可執(zhí)行地case語(yǔ)句盅藻,且有default語(yǔ)句,就會(huì)執(zhí)行default語(yǔ)句勃蜘。
4.如果沒(méi)有可運(yùn)行地case語(yǔ)句假残,且沒(méi)有default語(yǔ)句,select將阻塞阳惹,直到有case能執(zhí)行眶俩。