channel初步認識:
package main import "fmt" import "time" func main() { c := make(chan int) //初始化一個管道 defer close(c) //在main函式執行完畢之後執行。 go func() { //會開啟一個協程,並往管道c寫入資料 time.Sleep(2 * time.Second) fmt.Println("all ready") c <- 3 + 4 }() i := <-c // 將管道c的內容輸出賦值到i,在c還沒有內容的時候,會一直阻塞在這裡。 fmt.Println(i) //列印i的值 } [root@localhost hello]# go run channel.go all ready 7
如註釋所示,在管道還沒有內容輸入之前i := <-c這個語句一直被阻塞著。
往一個已經被close的channel中繼續傳送資料會導致run-time panic。
如下:
package main import "fmt" import "time" func main() { c := make(chan int) //初始化一個管道 go func() { //會開啟一個協程,並往管道c寫入資料 time.Sleep(2 * time.Second) fmt.Println("all ready") c <- 3 + 4 close(c) }() i := <-c // 將管道c的內容輸出賦值到i,在c還沒有內容的時候,會一直阻塞在這裡。 fmt.Println(i) //列印i的值 c <- 8 //由於c已經在協程裡面被關閉,這句將引起run-time panic } 輸出結果如下: [root@localhost hello]# go run channel.go all ready 7 panic: send on closed channel goroutine 1 [running]: main.main() /mnt/hgfs/share/eclipse/testgo/src/hello/channel.go:16 +0x125 exit status 2
可以使用一個額外的返回引數來檢查channel是否關閉。
x, ok := <-ch
如果OK 是false,表明接收的x是產生的零值,這個channel被關閉了或者為空。
另一種是可以用for range處理這種管道是否有資料的情況,在管道被關閉時for range會退出。
func main() { go func() { time.Sleep(1 * time.Hour) }() c := make(chan int) go func() { for i := 0; i < 10; i = i + 1 { c <- i } close(c) //如果將此句註釋掉,那麼下面的for range在列印完管道的內容後會一直阻塞。 }() for i := range c { fmt.Println(i) } fmt.Println("Finished") }
select 類似於switch,裡面的case可以是recieve或send或default語句。
如果同時有多個case滿足條件,那麼Go會偽隨機的選擇一個case處理,如果沒有case需要處理,則會選擇default去處理。如果沒有default case,則select語句會阻塞,直到某個case需要處理。
package main import ( "fmt" ) func fab(c, quit chan int) { x, y := 0, 1 for { select { case c <- x: x, y = y, x+y case <-quit: return } } } func main() { c := make(chan int) quit := make(chan int) go func() { for i := 0; i < 10; i++ { fmt.Println(<-c) } quit <- 0 }() fab(c, quit) } [root@localhost hello]# go run channel.go 0 1 1 2 3 5 8 13 21 34
超時處理:
package main import ( "fmt" "time" ) func main() { c := make(chan string) go func() { time.Sleep(30 * time.Second) c <- "Hello World" }() select { case res := <-c: fmt.Println(res) case <-time.After(2 * time.Second): fmt.Println("timeout") } } [root@localhost hello]# go run channel.go timeout
參考來源:http://colobu.com/2016/04/14/Golang-Channels/
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------