在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
Go Select使用 Go中的select和channel配合使用,通过select可以监听多个channel的I/O读写事件,当 IO操作发生时,触发相应的动作。 基本用法//select基本用法 select { case <- chan1: // 如果chan1成功读到数据,则进行该case处理语句 case chan2 <- 1: // 如果成功向chan2写入数据,则进行该case处理语句 default: // 如果上面都没有成功,则进入default处理流程 使用规则 1.如果没有default分支,select会阻塞在多个channel上,对多个channel的读/写事件进行监控。 2.如果有一个或多个IO操作可以完成,则Go运行时系统会随机的选择一个执行,否则的话,如果有default分支,则执行default分支语句,如果连default都没有,则select语句会一直阻塞,直到至少有一个IO操作可以进行。 快速返回同时监听不同的channel,做同一件工作,可以最快的返回结果。 package main import ( "fmt" "github.com/kirinlabs/HttpRequest" ) func main() { ch1 := make(chan int) ch2 := make(chan int) ch3 := make(chan int) go Getdata("https://www.baidu.com",ch1) go Getdata("https://www.baidu.com",ch2) go Getdata("https://www.baidu.com",ch3) select{ case v:=<- ch1: fmt.Println(v) case v:=<- ch2: fmt.Println(v) case v:=<- ch3: fmt.Println(v) } } func Getdata(url string,ch chan int){ req,err := HttpRequest.Get(url) if err != nil{ }else{ ch <- req.StatusCode() } } 随机返回同时监控不同的channel,配上default,select也不会阻塞。 package main import ( "fmt" "github.com/kirinlabs/HttpRequest" ) func main() { ch1 := make(chan int) ch2 := make(chan int) ch3 := make(chan int) go func(){ for { Getdata("https://www.baidu.com", ch1) Getdata("https://cn.bing.com", ch2) Getdata("https://cn.bing.com", ch3) } }() go func(){ for { select { case v := <-ch1: fmt.Println("信道1的结果:",v) case v := <-ch2: fmt.Println("信道2的结果:",v) case v := <-ch3: fmt.Println("信道3的结果:",v) default: continue } } }() select{} } func Getdata(url string,ch chan int){ req,err := HttpRequest.Get(url) if err != nil{ }else{ ch <- req.StatusCode() } } 通过select来检测channel的关闭事件func TestSelect1() { start := time.Now() c := make(chan interface{}) go func() { time.Sleep(2*time.Second) close(c) }() fmt.Println("Blocking on read...") select { case <-c: fmt.Printf("Unblocked %v later.\n", time.Since(start)) } } 注意:当close channel时,读取channel的一方会从channel中读取到value,false,此时的value一般情况下为nil。 通过channel通知,从而退出死循环func TestExitLoop() { done := make(chan interface{}) go func() { time.Sleep(2*time.Second) close(done) }() workCounter := 0 loop: for { select { case <-done: break loop default: } // Simulate work workCounter++ time.Sleep(1*time.Second) } fmt.Printf("在通知退出循环时,执行了%d次.\n", workCounter) } 启动一个goroutine,该goroutine在2s后,关闭channel。此时,主协程会在select中的case <-done分支中得到通知,跳出死循环。而在此之前,会执行default分支的代码,这里是什么都不做。 超时机制package main import ( "fmt" "time" ) func main() { ch := make(chan int) quit := make(chan bool) //新开一个协程 go func() { for { select { case num := <-ch: fmt.Println("num = ", num) case <-time.After(3 * time.Second): fmt.Println("超时") quit <- true } } }() for i := 0; i < 5; i++ { ch <- i time.Sleep(time.Second) } <-quit fmt.Println("程序结束") } 死锁与默认情况package main func main() { ch := make(chan string) select { case <-ch: } } 上面的程序中,我们在第 4 行创建了一个信道
如果存在默认情况,就不会发生死锁,因为在没有其他 case 准备就绪时,会执行默认情况。我们用默认情况重写后,程序如下: package main import "fmt" func main() { ch := make(chan string) select { case <-ch: default: fmt.Println("default case executed") } } 以上程序会输出:
如果 package main import "fmt" func main() { var ch chan string select { case v := <-ch: fmt.Println("received value", v) default: fmt.Println("default case executed") } } 在线运行程序 在上面程序中,
空 selectpackage main func main() { select {} } 我们已经知道,除非有
|
请发表评论