一、無緩存 channel
? ? ? ? 無緩沖channel 可用于兩個goroutine 之間 傳遞信號,比如以下示例:
? ? ? ? 順序打印1 至 100 的奇數和偶數:
import ("fmt""time"
)func main() {block := make(chan struct{})go odd(block)go even(block)time.Sleep(time.Second)fmt.Println("done")}func odd(block chan struct{}) {for i := 1; i < 100; i++ {<-blockif i%2 == 1 {fmt.Println("奇數:", i)}}
}func even(block chan struct{}) {for i := 1; i < 100; i++ {<-blockif i%2 == 0 {fmt.Println("偶數:", i)}}
}
上面這段代碼,我們使用一個無緩沖channel? 作為兩個gorountie 之間的信號傳遞的橋梁。
主子 goroutine? 之間傳遞信號
func main() {block := make(chan struct{})go func() {for i := 0; i < 10; i++ {fmt.Println(i)}close(block)}()<-blockfmt.Println("done")}
我們使用一個無緩沖channel 作為主子goroutine 之間的信號傳遞的橋梁,通過信號傳遞,主gorountine? 運行結束直接再退出。
二、有緩沖 channel
? ? ? ? 有緩沖channel? 可以作用于解耦操作,模擬消息隊列。“生產者”和“消費者”只需各自處理channel ,實現解耦。
? ? ? ? 解耦生產者和消費者。
func main() {task := make(chan int, 10)go consumer(task)//生成者for i := 0; i < 10; i++ {task <- i}time.Sleep(time.Second * 2)
}func consumer(task <-chan int) {for i := 0; i < 10; i++ {go func(id int) {t := <-taskfmt.Println(id, t)}(i)}
}
我們使用一個有緩沖的channel , 將生產者,消費者做解耦操作
輸出結果:
三、超時操作和定時器
? ? ? ?我們還可以通過select 和channel ,實現超時操作和定時器
? ? ? ? 超時操作:
import ("fmt""time"
)func main() {c1 := make(chan string, 1)go func() {time.Sleep(2 * time.Second)c1 <- "result 1"}()select {case res := <-c1:fmt.Println(res)case <-time.After(1 * time.Second):fmt.Println("timeout 1")}c2 := make(chan string, 1)go func() {time.Sleep(2 * time.Second)c2 <- "result 2"}()select {case res := <-c2:fmt.Println(res)case <-time.After(3 * time.Second):fmt.Println("timeout 1")}}
通過c1 和 c2 兩個channel ,分別模擬出超時和未超時場景
定時器:
func main() {ticker := time.NewTicker(500 * time.Millisecond)done := make(chan bool)go func() {for {select {case <-done:returncase t := <-ticker.C:fmt.Println("Tick at ", t)}}}()time.Sleep(1600 * time.Millisecond)ticker.Stop()done <- truefmt.Println("Ticker stopped")
}
我們定義一個打點器,每間隔500Ms執行一次操作,當打點stop時,通過一個無緩沖channel 傳遞退出信號
三、總結
本文我們介紹了一些關于 Channel 的使用方式,我們在閱讀完本文后可以了解無緩沖 channel 作為信號傳遞的使用方式和有緩沖 channel 解耦操作的方式,以及 channel 與 select 配合使用的用法。