1. 程式人生 > 其它 >每日一抄 Go語言使用select切換協程

每日一抄 Go語言使用select切換協程

看了兩篇部落格,一個說:在任何一個 case 中執行 break 或者 return,select 就結束了。
另一個說:break只能跳出select中的一個case
驗證了一下,不知道對不對,感覺是跳出了整個select

func main() {
	v := make(chan int)
	o := make(chan bool)

	select {
	case d := <-v:
		fmt.Println("ddd", d)
	case <-time.After(time.Second * 5):
		fmt.Println("timeout")
		//o <- true
		break
	}
	fmt.Println("ssssssssssssss")

	time.Sleep(time.Second * 100)
	<-o

	fmt.Println("程式結束")
}
package main

import (
	"fmt"
	"time"
)

/*
1.監聽的case中,沒有滿足條件的就阻塞
2.多個滿足的條件就任選一個執行
3.select本身不帶迴圈,需要外層的for迴圈
4.default通常不用,會產生忙輪訓
5.break只能跳出select中的一個case

1.加入了預設分支,那麼無論涉及通道操作的表示式是否有阻塞,select語句都不會被阻塞。如果那幾個表示式都阻塞了,或者說都沒有滿足求值的條件,那麼預設分支就會被選中並執行。

2.如果沒有加入預設分支,那麼一旦所有的case表示式都沒有滿足求值條件,那麼select語句就會被阻塞。直到至少有一個case表示式滿足條件為止。
如果select語句發現同時有多個候選分支滿足選擇條件,那麼它就會用一種偽隨機的演算法在這些分支中選擇一個並執行。注意,即使select語句是在被喚醒時發現的這種情況,也會這樣做
*/

/*
go裡面提供了一個關鍵字select,通過select可以監聽channel上的資料流動

select的用法與switch語言非常類似,由select開始一個新的選擇塊,每個選擇塊條件由case語句來描述

與switch語句可以選擇任何可使用相等比較的條件相比,select有比較多的限制,其中最大的一條限制就是每個case語句裡必須是一個IO操作
for{
	select {
	case <- chan1:
		//
	case <- chan2:
		//
	default:
		//case表示式都沒有滿足求值條件,
	}
}
*/

/*
在一個select語句中,go語言會按順序從頭到尾評估每一個傳送和接收的語句

如果其中的任意一語句可以繼續執行(即沒有被阻塞),那麼就從哪些可以執行的語句中任意選擇一條來使用

如果沒有任意一條語句可以執行(即所有的通道都被阻塞),那麼有兩種可能的情況:

如果給出了default語句,那麼就會執行default語句,同時程式的執行會從select語句後的語句中恢復
如果沒有default語句,那麼select語句將被阻塞,直到至少有一個通訊可以進行下去
*/

/*
防止channel超時機制
有時候會出現協程阻塞的情況,那麼我們如何避免這個情況?我們可以使用select來設定超時
*/

//func main() {
//	v := make(chan int)
//	o := make(chan bool)
//
//	select {
//	case d := <-v:
//		fmt.Println("ddd", d)
//	case <-time.After(time.Second * 5):
//		fmt.Println("timeout")
//		//o <- true
//		break
//	}
//	fmt.Println("ssssssssssssss")
//
//	time.Sleep(time.Second * 100)
//	<-o
//
//	fmt.Println("程式結束")
//}

//超時這種寫法也常常用來設定定時執行某段函式
//go func() {
//	select {
//	case <- time.After(5 * time.Second):
//		dosomething()
//	}
//}

/*
default 語句是可選的;fallthrough 行為,和普通的 switch 相似,是不允許的。在任何一個 case 中執行 break 或者 return,select 就結束了。

select 做的就是:選擇處理列出的多個通訊情況中的一個。

如果都阻塞了,會等待直到其中一個可以處理
如果多個可以處理,隨機選擇一個
如果沒有通道操作可以處理並且寫了default 語句,它就會執行:default 永遠是可執行的(這就是準備好了,可以執行)。
在 select 中使用傳送操作並且有 default 可以確保傳送不被阻塞!如果沒有 default,select 就會一直阻塞。

select 語句實現了一種監聽模式,通常用在(無限)迴圈中;在某種情況下,通過 break 語句使迴圈退出。

*/

func main() {
	ch1 := make(chan int)
	ch2 := make(chan int)

	go pump1(ch1)
	go pump2(ch2)
	go suck(ch1, ch2)
	time.Sleep(1e9)

}

func pump1(ch chan int) {
	for i := 0; ; i++ {
		ch <- i * 2
	}
}

func pump2(ch chan int) {
	for i := 0; ; i++ {
		ch <- i + 5
	}
}

func suck(ch1, ch2 chan int) {
	for {
		select {
		case v := <-ch1:
			fmt.Printf("Received on channel 1: %d\n", v)
		case u := <-ch2:
			fmt.Printf("Received on channel 2: %d\n", u)
		}
	}
}

/*
在程式 goroutine_select.go 中有 2 個通道 ch1 和 ch2,三個協程 pump1()、pump2() 和 suck()。
這是一個典型的生產者消費者模式。
在無限迴圈中,ch1 和 ch2 通過 pump1() 和 pump2() 填充整數;
suck() 也是在無限迴圈中輪詢輸入的,
通過 select 語句獲取 ch1 和 ch2 的整數並輸出。
選擇哪一個 case 取決於哪一個通道收到了資訊。程式在 main 執行 1 秒後結束。

-----------------------------------
©著作權歸作者所有:來自51CTO部落格作者宇宙之一粟的原創作品,請聯絡作者獲取轉載授權,否則將追究法律責任
Go 語言入門很簡單:使用 select 切換協程
https://blog.51cto.com/yuzhou1su/5416579
*/