go中的关键字-select
1. select的使用
定义:在golang里头select的功能与epoll(nginx)/poll/select的功能类似,都是坚挺IO操作,当IO操作发生的时候,触发相应的动作。
1.1 一些使用规范
在Go的语言规范中,select中的case的执行顺序是随机的,当有多个case都可以运行,select会随机公平地选出一个执行,其他的便不会执行:
package main import "fmt" func main() {
ch := make (chan int, ) ch<-
select {
case <-ch:
fmt.Println("随机一")
case <-ch:
fmt.Println("随机二n")
}
}
输出内容为随机一二里面的任意一个。
case后面必须是channel操作,否则报错;default子句总是可运行的,所以没有default的select才会阻塞等待事件 ;没有运行的case,那么将会阻塞事件发生报错(死锁)。
1.2 select的应用场景
timeout 机制(超时判断)
package main import (
"fmt"
"time"
) func main() {
timeout := make (chan bool, )
go func() {
time.Sleep(*time.Second) // 休眠1s,如果超过1s还没I操作则认为超时,通知select已经超时啦~
timeout <- true
}()
ch := make (chan int)
select {
case <- ch:
case <- timeout:
fmt.Println("超时啦!")
}
}
也可以这么写:
package main import (
"fmt"
"time"
) func main() {
ch := make (chan int)
select {
case <-ch:
case <-time.After(time.Second * ): // 利用time来实现,After代表多少时间后执行输出东西
fmt.Println("超时啦!")
}
}
判断channel是否阻塞(或者说channel是否已经满了)
package main import (
"fmt"
) func main() {
ch := make (chan int, ) // 注意这里给的容量是1
ch <-
select {
case ch <- :
default:
fmt.Println("通道channel已经满啦,塞不下东西了!")
}
}
退出机制
package main import (
"fmt"
"time"
) func main() {
i :=
ch := make(chan string, )
defer func() {
close(ch)
}() go func() {
DONE:
for {
time.Sleep(*time.Second)
fmt.Println(time.Now().Unix())
i++ select {
case m := <-ch:
println(m)
break DONE // 跳出 select 和 for 循环
default:
}
}
}() time.Sleep(time.Second * )
ch<-"stop"
}
2. select的实现
select-case中的chan操作编译成了if-else。如:
select {
case v = <-c:
...foo
default:
...bar
}
会被编译为:
if selectnbrecv(&v, c) {
...foo
} else {
...bar
}
类似地
select {
case v, ok = <-c:
... foo
default:
... bar
}
会被编译为:
if c != nil && selectnbrecv2(&v, &ok, c) {
... foo
} else {
... bar
}
selectnbrecv函数只是简单地调用runtime.chanrecv函数,不过是设置了一个参数,告诉当runtime.chanrecv函数,当不能完成操作时不要阻塞,而是返回失败。也就是说,所有的select操作其实都仅仅是被换成了if-else判断,底层调用的不阻塞的通道操作函数。
在Go的语言规范中,select中的case的执行顺序是随机的,那么,如何实现随机呢?
select和case关键字使用了下面的结构体:
struct Scase
{
SudoG sg; // must be first member (cast to Scase)
Hchan* chan; // chan
byte* pc; // return pc
uint16 kind;
uint16 so; // vararg of selected bool
bool* receivedp; // pointer to received bool (recv2)
};
struct Select
{
uint16 tcase; // 总的scase[]数量
uint16 ncase; // 当前填充了的scase[]数量
uint16* pollorder; // case的poll次序
Hchan** lockorder; // channel的锁住的次序
Scase scase[]; // 每个case会在结构体里有一个Scase,顺序是按出现的次序
};
每个select都对应一个Select结构体。在Select数据结构中有个Scase数组,记录下了每一个case,而Scase中包含了Hchan。然后pollorder数组将元素随机排列,这样就可以将Scase乱序了。
3. select死锁
select不注意也会发生死锁,分两种情况:
如果没有数据需要发送,select中又存在接收通道数据的语句,那么将发送死锁
package main
func main() {
ch := make(chan string)
select {
case <-ch:
}
}
预防的话加default。
空select,也会引起死锁。
package main func main() {
select {}
}
4. select和switch的区别
select
If multiple cases can proceed, a uniform pseudo-random choice is made to decide which single communication will execute.
package main import "time"
import "fmt"
func main() { c1 := make(chan string)
c2 := make(chan string) go func() {
time.Sleep(time.Second * ) c1 <- "one"
}() go func() {
time.Sleep(time.Second * ) c2 <- "two"
}() for i := ; i < ; i++ {
select { case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
switch
package main
import "fmt"
import "time" func main() {
i :=
fmt.Print("Write ", i, " as ")
switch i {
case :
fmt.Println("one")
case :
fmt.Println("two")
case :
fmt.Println("three")
}
switch time.Now().Weekday() {
case time.Saturday, time.Sunday:
fmt.Println("It's the weekend")
default:
fmt.Println("It's a weekday")
}
t := time.Now()
switch {
case t.Hour() < :
fmt.Println("It's before noon")
default:
fmt.Println("It's after noon")
}
whatAmI := func(i interface{}) {
switch t := i.(type) {
case bool:
fmt.Println("I'm a bool")
case int:
fmt.Println("I'm an int")
default:
fmt.Printf("Don't know type %T\n", t)
}
}
whatAmI(true)
whatAmI()
whatAmI("hey")
}
go中的关键字-select的更多相关文章
- 搜索sqlserver 存储过程中的关键字
搜索sqlserver 存储过程中的关键字 select * from sys.all_sql_modules where definition like '%SP_NAME%'
- SQLserver查询作业、视图、函数、存储过程中的关键字
一.查询视图.函数.存储过程中的关键字 SELECT a.name,a.[type],b.[definition] FROM sys.all_objects a,sys.sql_modules b W ...
- PostgreSQL中关于关键字(保留字)在表名和字段名中的应用文件解决
标识符和关键词 受限标识符或被引号修饰的标识符.它是由双引号(")包围的一个任意字符序列.一个受限标识符总是一个标识符而不会是一个关键字.因此"select"可以用于引用 ...
- 【SQL语句】 - 在所有存储过程中查找关键字,关键字不区分大小写 [sp_findproc]
USE [EShop]GO/****** Object: StoredProcedure [dbo].[sp_findproc] Script Date: 2015/8/19 11:05:24 *** ...
- 如何查询oracle中的关键字
如何查询oracle中的关键字,执行: select * from v$reserved_words
- 【C#学习笔记之一】C#中的关键字
C#中的关键字 关键字是对编译器具有特殊意义的预定义保留标识符.它们不能在程序中用作标识符,除非它们有一个 @ 前缀.例如,@if 是有效的标识符,但 if 不是,因为 if 是关键字. 下面是列出的 ...
- linq中let关键字学习
linq中let关键字就是对子查询的一个别名,let子句用于在查询中添加一个新的局部变量,使其在后面的查询中可见. linq中let关键字实例 1.传统下的子查询与LET关键字的区别 C# 代 ...
- C#中var关键字用法分析
原文连接 本文实例分析了C#中var关键字用法.分享给大家供大家参考.具体方法如下: C#关键字是伴随着.NET 3.5以后,伴随着匿名函数.LINQ而来, 由编译器帮我们推断具体的类型.总体来说,当 ...
- golang关键字select的三个例子, time.After模拟socket/心跳超时
golang关键字select的三个例子, time.After模拟socket/心跳超时 例子1 select会随机选择一个可执行的case // 这个例子主要说明select是随机选择一个 ...
随机推荐
- 常用windows命令
目录 本教程概述 用到的工具 标签 简介 1.cmd的一些规则 2.cd切换目录命令 3.dir显示目录命令 4.type显示文本内容 5.del 删除文件 6.查看IP地址 7.net 命令 8.n ...
- luogu P3878 [TJOI2010]分金币
[返回模拟退火略解] 题目描述 今有 nnn 个数 {ai}\{a_i\}{ai},把它们分成两堆{X},{Y}\{X\},\{Y\}{X},{Y},求一种分配使得∣∑i∈Xai−∑i∈Yai∣|\ ...
- SpringBootSecurity学习(26)前后端分离版之github单点登录
单点登录(SSO) 关于oauth2.0,最后我们再来学习一下单点登录.前面介绍过单点登录的定义,单点登录(Single Sign On),简称为 SSO,是目前比较流行的企业业务整合的解决方案之一. ...
- Java自动化测试框架-04 - TestNG之Test Method篇 - 道法自然,法力无边(详细教程)
简介 按照上一篇的计划,这一篇给小伙伴们分享一下测试方法. 一.设置参数 测试方法是可以带有参数的.每个测试方法都可以带有任意数量的参数,并且可以通过使用TestNG的@Parameters向方法传递 ...
- tomcat+Apache介绍
tomcat不是一个完整意义上的Jave EE服务器,它甚至都没有提供对哪怕是一个主要Java EE API的实现:但由于遵守apache开源协议,tomcat却又为众多的java应用程序服务器嵌入自 ...
- LaTeX常用篇(三)---矩阵与表格
目录 1. 序言 2. 矩阵 2.1 复杂写法 2.2 简化写法 2.3 复杂矩阵 3. 表格 4. 对齐 更新时间:2019.10.02 1. 序言 矩阵是一个强大的工具,许多东西都能够用矩阵来 ...
- 设计模式(九)Bridge模式
Bridge模式就是将类的功能层次结构和类的实现层次结构连接起来. 类的功能层次结构就是根据实际非抽象类来说的,也就是父类具有基本功能,然后在子类中增加新功能.用于增加新功能. 类的实现层次结构就是根 ...
- UIAlert
转自:https://blog.csdn.net/deng0zhaotai/article/details/53887508 通过uialertcontroller实现三种简易弹框 (一)警告类 - ...
- vue-music 跨域获取QQ音乐歌单接口
最近在看vue音乐APP视频学习,需要跨域获取歌单数据,视频中老师是在build/dev-server.js文件配置跨域接口的,但是新版的vue-cli是没有这个文件的,我的vue版本是"2 ...
- Oracle ADG环境搭建
部署 环境介绍 1,软件安装前基础部署 (两台做同样操作) 1.1,关闭selinux和防火墙 因为centos7里面没有/etc/sysconfig/iptables这个配置文件所以我们首先用yum ...