GO学习-(36) Go语言在select语句中实现优先级
Go语言在select语句中实现优先级
Go语言在select语句中实现优先级
select语句介绍
Go 语言中的 select
语句用于监控并选择一组case
语句执行相应的代码。它看起来类似于switch
语句,但是select
语句中所有case
中的表达式都必须是channel
的发送或接收操作。一个典型的select
使用示例如下:
select {
case <-ch1:
fmt.Println("liwenzhou.com")
case ch2 <- 1:
fmt.Println("q1mi")
}
Go 语言中的 select
关键字也能够让当前 goroutine
同时等待ch1
的可读和ch2
的可写,在ch1
和ch2
状态改变之前,select
会一直阻塞下去,直到其中的一个 channel
转为就绪状态时执行对应case
分支的代码。如果多个channel
同时就绪的话则随机选择一个case
执行。
除了上面展示的典型示例外,接下来我们逐一介绍一些select
的特殊示例。
空select
空select
指的是内部不包含任何case
,例如:
select{
}
空的 select
语句会直接阻塞当前的goroutine
,使得该goroutine
进入无法被唤醒的永久休眠状态。
只有一个case
如果select
中只包含一个case
,那么该select
就变成了一个阻塞的channel
读/写操作。
select {
case <-ch1:
fmt.Println("liwenzhou.com")
}
上面的代码,当ch1
可读时会执行打印操作,否则就会阻塞。
有default语句
如果select
中还可以包含default
语句,用于当其他case
都不满足时执行一些默认操作。
select {
case <-ch1:
fmt.Println("liwenzhou.com")
default:
time.Sleep(time.Second)
}
上面的代码,当ch1
可读时会执行打印操作,否则就执行default
语句中的代码,这里就相当于做了一个非阻塞的channel
读取操作。
总结
select
不存在任何的case
:永久阻塞当前 goroutineselect
只存在一个case
:阻塞的发送/接收select
存在多个case
:随机选择一个满足条件的case
执行select
存在default
,其他case
都不满足时:执行default
语句中的代码
如何在select中实现优先级
已知,当select
存在多个 case
时会随机选择一个满足条件的case
执行。
现在我们有一个需求:我们有一个函数会持续不间断地从ch1
和ch2
中分别接收任务1和任务2,
如何确保当ch1
和ch2
同时达到就绪状态时,优先执行任务1,在没有任务1的时候再去执行任务2呢?
高级Go语言程序员小明挠了挠头写出了如下函数:
func worker(ch1, ch2 <-chan int, stopCh chan struct{}) {
for {
select {
case <-stopCh:
return
case job1 := <-ch1:
fmt.Println(job1)
default:
select {
case job2 := <-ch2:
fmt.Println(job2)
default:
}
}
}
}
上面的代码通过嵌套两个select
实现了”优先级”,看起来是满足题目要求的。但是这代码有点问题,如果ch1
和ch2
都没有达到就绪状态的话,整个程序不会阻塞而是进入了死循环。
怎么办呢?
小明又挠了挠头,又写下了另一个解决方案:
func worker2(ch1, ch2 <-chan int, stopCh chan struct{}) {
for {
select {
case <-stopCh:
return
case job1 := <-ch1:
fmt.Println(job1)
case job2 := <-ch2:
priority:
for {
select {
case job1 := <-ch1:
fmt.Println(job1)
default:
break priority
}
}
fmt.Println(job2)
}
}
}
这一次,小明不仅使用了嵌套的select
,还组合使用了for
循环和LABEL
来实现题目的要求。上面的代码在外层select
选中执行job2 := <-ch2
时,进入到内层select
循环继续尝试执行job1 := <-ch1
,当ch1
就绪时就会一直执行,否则跳出内层select
。
实际应用场景
上面的需求虽然是我编的,但是关于在select
中实现优先级在实际生产中是有实际应用场景的,例如K8s的controller中就有关于上面这个技巧的实际使用示例,这里在关于select
中实现优先级相关代码的关键处都已添加了注释,具体逻辑这里就不展开细说了。
// kubernetes/pkg/controller/nodelifecycle/scheduler/taint_manager.go
func (tc *NoExecuteTaintManager) worker(worker int, done func(), stopCh <-chan struct{}) {
defer done()
// 当处理具体事件的时候,我们会希望 Node 的更新操作优先于 Pod 的更新
// 因为 NodeUpdates 与 NoExecuteTaintManager无关应该尽快处理
// -- 我们不希望用户(或系统)等到PodUpdate队列被耗尽后,才开始从受污染的Node中清除pod。
for {
select {
case <-stopCh:
return
case nodeUpdate := <-tc.nodeUpdateChannels[worker]:
tc.handleNodeUpdate(nodeUpdate)
tc.nodeUpdateQueue.Done(nodeUpdate)
case podUpdate := <-tc.podUpdateChannels[worker]:
// 如果我们发现了一个 Pod 需要更新,我么你需要先清空 Node 队列.
priority:
for {
select {
case nodeUpdate := <-tc.nodeUpdateChannels[worker]:
tc.handleNodeUpdate(nodeUpdate)
tc.nodeUpdateQueue.Done(nodeUpdate)
default:
break priority
}
}
// 在 Node 队列清空后我们再处理 podUpdate.
tc.handlePodUpdate(podUpdate)
tc.podUpdateQueue.Done(podUpdate)
}
}
}
GO学习-(36) Go语言在select语句中实现优先级的更多相关文章
- 【MYSQL】update/delete/select语句中的子查询
update或delete语句里含有子查询时,子查询里的表不能在update或是delete语句中,如含有运行时会报错:但select语句里含有子查询时,子查询里的表可以在select语句中. 如:把 ...
- SQL SERVER SELECT语句中加锁选项的详细说明 [转]
SQL Server提供了强大而完备的锁机制来帮助实现数据库系统的并发性和高性能.用户既能使用SQL Server的缺省设置也可以在select 语句中使用“加锁选项”来实现预期的效果. 本文介绍了S ...
- select语句中会影响查询效率的因素
1.没有创建索引,或者没有正确使用索引;2.存在死锁的情况,从而导致select语句挂起; 3.返回不必要的列,如很多人喜欢在程序中使用select * from 这样会查询表或视图中的所有字段,如果 ...
- SQL SERVER SELECT语句中加锁选项的详细说明
共享锁(读锁)和排他锁(写锁) 共享锁(S锁):共享 (S) 用于不更改或不更新数据的操作(只读操作),如 SELECT 语句. 如果事务T对数据A加上共享锁后,则其他事务只能对A再加共享锁,不能 ...
- 关于Mysql select语句中拼接字符串的记录
在mysql的SELECT语句中拼接两列(或多列)的字符串显示: mysql> select concat(dname,loc) from dept; 以上语句便把dept表的dname,loc ...
- MySQL 语句中执行优先级——and比or高
转: MySQL 语句中执行优先级——and比or高 2017年04月20日 13:33:03 十步行 阅读数:7381 版权声明:本文为博主原创文章,未经博主允许不得转载. https://bl ...
- 【SQL学习笔记】一、select语句
SQL有别于其他的编程语言的一点在于首先处理的并不是写在第一行的语句(select),而是from字句. 为了更详细的了解select语句的每个部分,举例如下: 该语句返回的结果是下订单超过4次的女顾 ...
- oracle(3)select语句中常用的关键字说明
1.select 查询表中的数据 select * from stu: ---查询stu表所有的数据,*代表所有2.dual ,伪表,要查询的数据不存在任何表中时使用 select sysdate f ...
- SELECT语句中的for update的用法(锁的运用)
回复1:一般FOR UPDATE用在PL/SQL的游标里,它的作用就是一个行级锁(对游标里所有的记录),如果其他进程要更新这个游标行级锁里的记录,就必须等待当前进程的COMMIT或者回滚. 该语句用来 ...
随机推荐
- 基于.Net Core 5.0 Worker Service 的 Quart 服务
前言 看过我之前博客的人应该都知道,我负责了相当久的部门数据同步相关的工作.其中的艰辛不赘述了. 随着需求的越来越复杂,最近windows的计划任务已经越发的不能满足我了,而且计划任务毕竟太弱智,总是 ...
- 【秒懂音视频开发】21_显示BMP图片
文本的主要内容是:使用SDL显示一张BMP图片,算是为后面的<播放YUV>做准备. 为什么是显示BMP图片?而不是显示JPG或PNG图片? 因为SDL内置了加载BMP的API,使用起来会更 ...
- 1.7.8- HTML合并单元格
跨行与跨列
- 总结:composer的install和require和update指令。到底什么时候用什么指令
https://packagist.org 相当于是应用商店
- 《机器学习Python实现_10_09_集成学习_bagging_stacking原理及实现》
介绍 前面对模型的组合主要用了两种方式: (1)一种是平均/投票: (2)另外一种是加权平均/投票: 所以,我们有时就会陷入纠结,是平均的好,还是加权的好,那如果是加权,权重又该如何分配的好?如果我们 ...
- windows CMD实现的信息收集工具
bat1 @echo off echo ====================================================== echo [*] 所有盘符下的有趣文件 @For ...
- 查找和定位Android应用的按钮点击事件的代码位置基于Xposed Hook实现
本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80956455 在进行Android程序的逆向分析的时候,经常需要通过Androi ...
- 续订Jetbrain学生包
今天打开IDEA和Pycharm都不约而同的告诉我我的账号无法使用学生包了 此刻我的内心是: 冷静下来我算了算,嗷,原来是一年的订阅期到了,那就简单了,直接续订吧,唉.其实续订和重新认证是一样的. 首 ...
- ThinkPHP5查询-select与find理解
出现问题 在tp5框架中判断select查询结果是否为空时,无论查询条件是否满足,判断查询结果都不为空 解析问题 select查询的是多条数据,若查询数据为空,则返回一个空的二维数组 array(ar ...
- 在服务器上使用 smart http 搭建 Git 服务器
前言 最近一直在写 django 网页的代码,随着代码的量越来越大,管理起来也有点复杂(当然,有在使用 git 进行代码管理).同时由于有不同的工作环境,有些工作环境对 ssh 的访问有限制,所以想到 ...