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使用的更多相关文章

  1. 最全的ORACLE-SQL笔记

    -- 首先,以超级管理员的身份登录oracle sqlplus sys/bjsxt as sysdba --然后,解除对scott用户的锁 alter user scott account unloc ...

  2. Matplotlib数据可视化(6):饼图与箱线图

    In [1]: from matplotlib import pyplot as plt import numpy as np import matplotlib as mpl mpl.rcParam ...

  3. SELECT INTO 和 INSERT INTO SELECT 两种表复制语句

    Insert是T-sql中常用语句,Insert INTO table(field1,field2,...) values(value1,value2,...)这种形式的在应用程序开发中必不可少.但我 ...

  4. select、poll、epoll之间的区别总结

    select.poll.epoll之间的区别总结 05/05. 2014 select,poll,epoll都是IO多路复用的机制.I/O多路复用就通过一种机制,可以监视多个描述符,一旦某个描述符就绪 ...

  5. LINQ to SQL Select查询

    1. 查询所有字段 using (NorthwindEntities context = new NorthwindEntities()) { var order = from n in contex ...

  6. ADO.NET一小记-select top 参数问题

    异常处理汇总-后端系列 http://www.cnblogs.com/dunitian/p/4523006.html 最近使用ADO.NET的时候,发现select top @count xxxx 不 ...

  7. iosselect:一个js picker项目,在H5中实现IOS的select下拉框效果

    具体文档和demo可以访问github:https://github.com/zhoushengmufc/iosselect 移动端浏览器对于select的展示样式是不一致的,ios下是类似原生的pi ...

  8. SQL Server中SELECT会真的阻塞SELECT吗?

    在SQL Server中,我们知道一个SELECT语句执行过程中只会申请一些意向共享锁(IS) 与共享锁(S), 例如我使用SQL Profile跟踪会话86执行SELECT * FROM dbo.T ...

  9. (转载) Linux IO模式及 select、poll、epoll详解

    注:本文是对众多博客的学习和总结,可能存在理解错误.请带着怀疑的眼光,同时如果有错误希望能指出. 同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案 ...

  10. 基于select的python聊天室程序

    python网络编程具体参考<python select网络编程详细介绍>. 在python中,select函数是一个对底层操作系统的直接访问的接口.它用来监控sockets.files和 ...

随机推荐

  1. Greenwich.SR2版本的Spring Cloud Config+BUS实例

    Spring Cloud Config统一的配置中心同注册中心Eureka一样,也分服务端和客户端.服务端用来保存配置信息,客户端用来读取.它的优势是基于Git仓库,支持多环境.多分支配置.动态刷新. ...

  2. Linux下开发常用配置

    JDK /etc/profile export JAVA_HOME=/usr/local/jdk1.8.0_181export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.ja ...

  3. checkbox 在移动端显示为小圆圈问题

    在desktop显示正常,但是在移动端显示变为小圆圈,无法正确展示选中取消选中效果问题解决方案: display: block; width: 58px; height: 20px; -webkit- ...

  4. Core Data 多表关联

    1.概念简介 coreData中存在复杂的数据关系时,一张表难以满足需求,此时就需要了解使用coreData多表的关联使用. 如 课程表 和 章节表 的关系:一个课程跟章节的对应关系是 一对多,单一个 ...

  5. 【ARTS】01_39_左耳听风-201900805~20190811

    ARTS: Algrothm: leetcode算法题目 Review: 阅读并且点评一篇英文技术文章 Tip/Techni: 学习一个技术技巧 Share: 分享一篇有观点和思考的技术文章 Algo ...

  6. SQL Server数据同步交换

    一.为了解决数据同步汇聚,数据分发,数据转换,数据维护等需求,TreeSoft将复杂的网状的同步链路变成了星型数据链路.     TreeSoft作为中间传输载体负责连接各种数据源,为各种异构数据库之 ...

  7. (1) laravel php artisan list make

    php artisan list make Laravel Framework 5.4.36 Usage: command [options] [arguments] Options: -h, --h ...

  8. vue中的$listeners属性作用

    一.当组件的根元素不具备一些DOM事件,但是根元素内部元素具备相对应的DOM事件,那么可以使用$listeners获取父组件传递进来的所有事件函数,再通过v-on="xxxx"绑定 ...

  9. mac 已损坏 移至废纸篓

    1.问题描述: 从网页下载的安装包,总是提示“已损坏,移至废纸篓”这类的信息 2.原因: 系统版本过高,对安全性进行了校验. 3.解决方案:命令行输入以下命令,然后输入密码 sudo spctl -- ...

  10. 腾讯云+阿里云 搭建hadoop + hbase

    目录 服务器配置 hadoop hbase JAVA测试 历时两天,踩了无数坑最后搭建成功... 准备 两台服务器都安装jdk1.8(最好装在相同路径). hadoop 下载 hbase 下载 这里使 ...