channel的建立和關閉:
ch:=make(chan int) ,初始化一個int類型的channel
使用Go内置函數close來關閉一個channel, close(ch)
注意:
1.向一個已經關閉的channel發送消息會程式會panic
2.關閉一個未初始化的channel會panic
3.可以從一個已經關閉的channel中讀取消息,能夠讀取channel中未被讀取的消息,如果所有消息均被讀出,則會讀到類型的零值。從一個已經關閉的channel中讀取消息永遠不會阻塞,ok,idiom:=<-ch, 如果ok為真則未關閉,false則已經關閉。
4.channel關閉時候,所有的goroutine都會受到消息
無緩存的channel
從無緩存的channel中讀取消息會阻塞,直到有goroutine向此channel中發送消息,向無緩存的channel中發消息也會阻塞,直到有goroutine向該channel中讀取消息。
執行個體代碼:
//讀資料
var ch chan int
ch = make(chan int)
//close(ch)
go func() {
fmt.Println("A")
_ = <-ch //阻塞在這裡,不會列印B
fmt.Println("B")
}()
time.Sleep(time.Second * time.Duration(5))
//存資料
var ch chan int
ch = make(chan int)
//close(ch)
go func() {
fmt.Println("A")
ch <- 8 //阻塞在這裡,不會列印B
fmt.Println("B")
}()
有緩存的channel
有緩存的 channel 類似一個阻塞隊列(采用環形數組實作)。當緩存未滿時,向 channel 中發送消息時不會阻塞,當緩存滿時,發送操作将被阻塞,直到有其他 goroutine 從中讀取消息;相應的,當 channel 中消息不為空時,讀取消息不會出現阻塞,當 channel 為空時,讀取操作會造成阻塞,直到有 goroutine 向 channel 中寫入消息
make函數的第二個參數來指定緩存的容量
執行個體代碼:
var ch chan int
ch = make(chan int,1)
//close(ch)
go func() {
fmt.Println("A")
_ = <-ch //阻塞,盡管有緩存,但是channel是空的沒有放入消息
fmt.Println(”B”)
_ = <-ch //阻塞,不會列印C
fmt.Println("C")
}()
time.Sleep(time.Second * time.Duration(5))
channel的周遊
注意:channel可以用range取值,并且一直會從channel中取值,直到有goroutine把channel關閉循環才會結束。
示例代碼:
var ch chan int
ch = make(chan int, 0)
go func() {
for v := range ch { //循環直到有goroutine close(ch)
fmt.Println(v)
}
}()
ch <- 1
ch <- 2
ch <- 3
time.Sleep(time.Second * 5) //睡眠5
ch <- 4
ch <- 5
close(ch)
輸出:12345,其中45是在main函數睡眠5秒後輸出,range一直在持續,直到close(ch)
也可以使用 :
for {
c, ok := <-ch
if !ok {
break
}
}
這種方式來周遊。
select和channel的配合使用
注意:
1.select可以同時監聽多個channel的寫入或讀取
2.執行select若隻有一個case不阻塞,則執行這個case塊
3.若多個case不阻塞,則随機挑選一個執行
4.若所有case都阻塞則實行default塊,若未定義default則select語句阻塞
直到有case被喚醒
5.使用break跳出select
示例代碼:
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
ch4 := make(chan int)
select {
case <-ch1:
fmt.Println("A")
case <-ch2:
fmt.Println("B")
case <-ch3:
fmt.Println("C")
case <-ch4:
fmt.Println("D")
default:
fmt.Println("E") //全部阻塞,執行default
}
fmt.Println("F")
示例代碼2:
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
ch4 := make(chan int)
go func() {
fmt.Println("1")
ch1 <- 1
fmt.Println("2")
ch2 <- 2
fmt.Println("3")
ch3 <- 3
}()
time.Sleep(time.Second * 1)
select {
case <-ch1:
fmt.Println("A")
case <-ch2:
fmt.Println("B")
case <-ch3:
fmt.Println("C")
case <-ch4:
fmt.Println("D")
default:
//fmt.Println("E") //全部阻塞,執行default
}
fmt.Println("F")
//輸出: 1
// A
// F
// 2
首先執行goroutine 會列印1 此時給ch1指派 會阻塞,1秒後當執行select 則case ch1通過列印A,此時 goroutine 被喚醒 同時main函數也會繼續執行 則列印F、2,main函數退出 .