Golang select的使用及典型用法
基本使用
- select是Go中的一个控制结构,类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。
select中的case语句必须是一个channel操作
select中的default子句总是可运行的。
- 如果有多个case都可以运行,select会随机公平地选出一个执行,其他不会执行。
- 如果没有可运行的case语句,且有default语句,那么就会执行default的动作。
- 如果没有可运行的case语句,且没有default语句,select将阻塞,直到某个case通信可以运行
例如:
package main
import "fmt"
func main() {
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
}
//输出:no communication
典型用法
1.超时判断
//比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行
var resChan = make(chan int)
// do request
func test() {
select {
case data := <-resChan:
doData(data)
case <-time.After(time.Second * 3):
fmt.Println("request time out")
}
}
func doData(data int) {
//...
}
2.退出
//主线程(协程)中如下:
var shouldQuit=make(chan struct{})
fun main(){
{
//loop
}
//...out of the loop
select {
case <-c.shouldQuit:
cleanUp()
return
default:
}
//...
}
//再另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行
close(shouldQuit)
3.判断channel是否阻塞
//在某些情况下是存在不希望channel缓存满了的需求的,可以用如下方法判断
ch := make (chan int, 5)
//...
data:=0
select {
case ch <- data:
default:
//做相应操作,比如丢弃data。视需求而定
}
举一个有趣的列子:使用channel将异步变为同步
题目如下:
存在以下代码,请问如何实现print函数可以顺序输出1~75,要求不使用锁,只能使用channel
func main() {
for i := 1; i < 75; i++ {
go print(i)
}
time.Sleep(5*time.Second) //wait all goroutine
}
func print(i int){
}
实现完整代码如下:
package main
import (
"fmt"
"time"
)
var ch = make(chan int)
func main() {
for i := 1; i <= 75; i++ {
go print(i)
ch <- 0
}
time.Sleep(5 * time.Second) //wait all goroutines
}
func print(i int) {
<-ch
fmt.Println(i)
}