004_关于go的select

一、

【使用 select 实现 timeout 机制】

如下:

timeout := make (chan bool, 1)
go func() {
    time.Sleep(1e9) // sleep one second
    timeout <- true
}()
ch := make (chan int)
select {
case <- ch:
case <- timeout:
    fmt.Println("timeout!")
}

输出=>timeout! 

当超时时间到的时候,case2 会操作成功。 所以 select 语句则会退出。 而不是一直阻塞在 ch 的读取操作上。 从而实现了对 ch 读取操作的超时设置。

下面这个更有意思一点。

当 select 语句带有 default 的时候:

ch1 := make (chan int, 1)
ch2 := make (chan int, 1)

select {
case <-ch1:
    fmt.Println("ch1 pop one element")
case <-ch2:
    fmt.Println("ch2 pop one element")
default:
    fmt.Println("default")
}

输出=>default

此时因为 ch1 和 ch2 都为空,所以 case1 和 case2 都不会读取成功。 则 select 执行 default 语句。

就是因为这个 default 特性, 我们可以使用 select 语句来检测 chan 是否已经满了。

如下:

ch := make (chan int, 1)
ch <- 1
select {
case ch <- 2:
default:
    fmt.Println("channel is full !")
}

输出=>channel is full !

因为 ch 插入 1 的时候已经满了, 当 ch 要插入 2 的时候,发现 ch 已经满了(case1 阻塞住), 则 select 执行 default 语句。 这样就可以实现对 channel 是否已满的检测, 而不是一直等待。

比如我们有一个服务, 当请求进来的时候我们会生成一个 job 扔进 channel, 由其他协程从 channel 中获取 job 去执行。 但是我们希望当 channel 瞒了的时候, 将该 job 抛弃并回复 【服务繁忙,请稍微再试。】 就可以用 select 实现该需求。

二、

Go的select关键字可以让你同时等待多个通道操作,将协程(goroutine),通道(channel)和select结合起来构成了Go的一个强大特性。

package main

import "time"
import "fmt"

func main() {

	// 本例中,我们从两个通道中选择
	c1 := make(chan string)
	c2 := make(chan string)

	// 为了模拟并行协程的阻塞操作,我们让每个通道在一段时间后再写入一个值
	go func() {
		time.Sleep(time.Second * 1)
		c1 <- "one"
	}()
	go func() {
		time.Sleep(time.Second * 2)
		c2 <- "two"
	}()

	// 我们使用select来等待这两个通道的值,然后输出
	for i := 0; i < 2; i++ {
		select {
		case msg1 := <-c1:
			fmt.Println("received", msg1)
		case msg2 := <-c2:
			fmt.Println("received", msg2)
		}
	}
}
/*输出=>
received one
received two
*/

如我们所期望的,程序输出了正确的值。对于select语句而言,它不断地检测通道是否有值过来,一旦发现有值过来,立刻获取输出。

 

参考:

https://yanyiwu.com/work/2014/11/08/golang-select-typical-usage.html

https://www.kancloud.cn/itfanr/go-by-example/81706

posted @ 2017-11-19 11:49  arun_python  阅读(108)  评论(0)    收藏  举报