Golang select详解

golang 中的 select 就是用来监听和 channel 有关的 IO 操作,当 IO 操作发生时,触发相应的动作。select 只能应用于 channel 的操作,既可以用于 channel 的数据接收,也可以用于 channel 的数据发送。如果 select 的多个分支都满足条件,则会随机的选取其中一个满足条件的分支执行。

1,Golang select基本用法


语法

select {
	case <- chan1:
		// 如果 chan1 成功读到数据,则进行该 case 处理语句
	case chan2 <- 1:
		// 如果成功向 chan2 写入数据,则进行该 case 处理语句
	default:
		// 如果上面都没有成功,则进入default处理流程
}


说明
select 里面即可以对 channel 进行读取,还可以对 channel 进行写入,如果所有条件都不满足,并且有 default 子句,则执行 default 子句,否则,会阻塞。
Golang select典型用法
阻塞
所有条件都不满足,则永久阻塞

package main import ( "fmt" ) func main() {
 	fmt.Println("嗨客网(www.haicoder.net)") 	
        ch := make(chan int, 1) 	
        select { case <-ch:fmt.Println("Received from ch") } 
} 

程序运行后,输出如下图所示:

我们看到,此时,程序死锁了,因为 select 中永远不可能有满足的条件,即,select 会永久阻塞。
执行默认分支
如果有 default 分支,并且所有条件都不满足,则执行 default 分支

package main import ( 	"fmt" ) 
func main() { 	
    fmt.Println("嗨客网(www.haicoder.net)") 	
    ch := make(chan int, 1) 	
    select { 
        case <-ch: fmt.Println("Received from ch") 
    default: 		
        fmt.Println("Run in default") 	
    } 
} 

程序运行后,输出如下图所示:

我们看到,此时,select 中的所有条件都不满足,因此,执行了 default 字句。
执行分支
如果有满足的分支,则执行对应的分支

package main import ( 	"fmt" ) 
func main() { 	
    fmt.Println("嗨客网(www.haicoder.net)") 	
    ch := make(chan int, 1) 	
    ch <- 1024 
    select { 	
    case val := <-ch: 		
        fmt.Println("Received from ch, val =", val) 	
    default: 		
        fmt.Println("Run in default") 	
    } 
} 

程序运行后,输出如下图所示:


我们看到,此时,select 中的第一个分支与 default 分支同时都满足,执行了第一个分支。
多个分支同时满足
如果多个分支同时满足,则随机选择执行

package main import ( 	"fmt" ) 
func main() { 	
    fmt.Println("嗨客网(www.haicoder.net)") 	
    ch := make(chan int, 1) 	
    ch <- 1024 
    select { 	
        case val := <-ch: 		
            fmt.Println("Received from ch1, val =", val) 	
        case val := <-ch: 		
            fmt.Println("Received from ch2, val =", val) 	
        case val := <-ch: 		
            fmt.Println("Received from ch3, val =", val) 	
        default: 		
            fmt.Println("Run in default") 	
    } 
} 


程序运行后,输出如下图所示:

我们多运行几次,发现,第一个 case、第二个 case 和第三个 case 都会被执行,即,此时所有条件都满足,则随机选择一个 case 执行。
超时机制
select 可以用于控制超时

package main import ( 	"fmt" "time" ) 
func main() { 	
    fmt.Println("嗨客网(www.haicoder.net)") 	
    timeout := make(chan bool, 1) 	
    ch := make(chan int) 	
    go func() { 		
        time.Sleep(2 * time.Second) 		
        timeout <- true }() 	
    select { 	
        case <-ch: 		
        fmt.Println("received from ch") 	
        case <-timeout: 		
        fmt.Println("select timeout") 	
    } 
} 

程序运行后,输出如下图所示:

这里,我们使用了 sleep 模拟了超时。
select time.After
select 可以用 time.After 控制超时

package main import ( 	"fmt" "time" ) 
func main() { 	
    fmt.Println("嗨客网(www.haicoder.net)") 	
    ch := make(chan int) 	
    select { 	
        case <-ch: 		
            fmt.Println("received from ch") 	
        case <-time.After(time.Second * 2): 		
            fmt.Println("select timer after timeout") 	
    }
 } 

程序运行后,输出如下图所示:


这里,我们使用了 time.After 实现了超时控制。
select和for循环使用
可以在 for 循环里面使用 select

package main import ( 	"fmt" "time" ) 
func main() { 	
    fmt.Println("嗨客网(www.haicoder.net)") 	
    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" 	}() 	
    for i := 0; i < 2; i++ { 		
        select { 		
            case msg1 := <-c1: 			
                fmt.Println("received", msg1) 		
            case msg2 := <-c2: 			
                fmt.Println("received", msg2) 		
         } 	
     } 
} 

程序运行后,输出如下图所示:


我们在 for 循环里面使用了 select。
Golang select使用总结
golang 中的 select 就是用来监听和 channel 有关的 IO 操作,当 IO 操作发生时,触发相应的动作。
select 只能应用于 channel 的操作,既可以用于 channel 的数据接收,也可以用于 channel 的数据发送。如果 select 的多个分支都满足条件,则会随机的选取其中一个满足条件的分支执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值