Go Select使用
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时,关闭channel的情况。
通过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 行创建了一个信道 ch
。我们在 select
内部(第 6 行),试图读取信道 ch。由于没有 Go 协程向该信道写入数据,因此 select
语句会一直阻塞,导致死锁。该程序会触发运行时 panic
,报错信息如下:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan receive]:
main.main()
/tmp/sandbox416567824/main.go:6 +0x80
如果存在默认情况,就不会发生死锁,因为在没有其他 case 准备就绪时,会执行默认情况。我们用默认情况重写后,程序如下:
package main import "fmt" func main() {
ch := make(chan string)
select {
case <-ch:
default:
fmt.Println("default case executed")
}
}
以上程序会输出:
default case executed
如果 select
只含有值为 nil
的信道,也同样会执行默认情况。
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") }
}
在线运行程序
在上面程序中,ch
等于 nil
,而我们试图在 select
中读取 ch
(第 8 行)。如果没有默认情况,select
会一直阻塞,导致死锁。由于我们在 select
内部加入了默认情况,程序会执行它,并输出:
default case executed
空 select
package main
func main() {
select {}
}
我们已经知道,除非有 case
执行,select
语句就会一直阻塞着。在这里,select
语句没有任何 case
,因此它会一直阻塞,导致死锁。该程序会触发 panic
,输出如下:
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [select (no cases)]:
main.main()
/tmp/sandbox299546399/main.go:4 +0x20
Go Select使用的更多相关文章
- 最全的ORACLE-SQL笔记
-- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unloc ...
- Matplotlib数据可视化(6):饼图与箱线图
In [1]: from matplotlib import pyplot as plt import numpy as np import matplotlib as mpl mpl.rcParam ...
- SELECT INTO 和 INSERT INTO SELECT 两种表复制语句
Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少.但我 ...
- select、poll、epoll之间的区别总结
select.poll.epoll之间的区别总结 05/05. 2014 select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪 ...
- LINQ to SQL Select查询
1. 查询所有字段 using (NorthwindEntities context = new NorthwindEntities()) { var order = from n in contex ...
- ADO.NET一小记-select top 参数问题
异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 最近使用ADO.NET的时候,发现select top @count xxxx 不 ...
- iosselect:一个js picker项目,在H5中实现IOS的select下拉框效果
具体文档和demo可以访问github:https://github.com/zhoushengmufc/iosselect 移动端浏览器对于select的展示样式是不一致的,ios下是类似原生的pi ...
- SQL Server中SELECT会真的阻塞SELECT吗?
在SQL Server中,我们知道一个SELECT语句执行过程中只会申请一些意向共享锁(IS) 与共享锁(S), 例如我使用SQL Profile跟踪会话86执行SELECT * FROM dbo.T ...
- (转载) Linux IO模式及 select、poll、epoll详解
注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...
- 基于select的python聊天室程序
python网络编程具体参考<python select网络编程详细介绍>. 在python中,select函数是一个对底层操作系统的直接访问的接口.它用来监控sockets.files和 ...
随机推荐
- 阶段5 3.微服务项目【学成在线】_day18 用户授权_01-用户授权业务流程分析
1 用户授权业务流程 用户授权的业务流程如下: 业务流程说明如下: 1.用户认证通过,认证服务向浏览器cookie写入token( 身份令牌) 2.前端携带token请求用户中心服务获取jwt令牌 前 ...
- PAT 甲级 1045 Favorite Color Stripe (30 分)(思维dp,最长有序子序列)
1045 Favorite Color Stripe (30 分) Eva is trying to make her own color stripe out of a given one. S ...
- 第一个php文件运行
运行会发现报错,解决参考:写的很详细 http://blog.csdn.net/meegomeego/article/details/36020553
- 简单的django登录项目---带views视图函数(脚本文件)---用Bootstrap
简单的django登录项目 1.首先建立工程,建立工程请参照:https://www.cnblogs.com/effortsing/p/10394511.html 2.在Firstdjango工程项目 ...
- PostgreSQL学习笔记——窗口函数
在学习窗口函数之前,我们新建一个Product表并往其中插入一些数据: drop table if exists Product; create table Product ( product_id ...
- iframe重定向让父页面跳转
情景描述 我们在使用一些后台程序的html模板(比如H-ui)的时候,这些html前端程序是iframe版的, 也就是说在使用的时候,每当我点击左侧导航栏的一个按钮,在右侧就会弹出一个菜单栏,在显示的 ...
- 关于LSTM的输入和训练过程的理解
1.训练的话一般一批一批训练,即让batch_size 个样本同时训练: 2.每个样本又包含从该样本往后的连续seq_len个样本(如seq_len=15),seq_len也就是LSTM中cell的个 ...
- 整理Vue.js 面试题
Vue.js 面试题整理 Vue项目结构介绍 build 文件夹:用于存放 webpack 相关配置和脚本. config 文件夹:主要存放配置文件,比如配置开发环境的端口号.开启热加载或开启gz ...
- Kotlin教程
Kotlin是一种静态类型的编程语言,由JetBrains开发.如果你有Java的基础知识,你很快就能学会Kotlin.这个Kotlin教程是为初学者设计的,因此即使您不了解Java,也可以理解Kot ...
- 最新 哔哩哔哩java校招面经 (含整理过的面试题大全)
从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.哔哩哔哩等10家互联网公司的校招Offer,因为某些自身原因最终选择了哔哩哔哩.6.7月主要是做系统复习.项目复盘.Leet ...