顺晟科技
2021-06-16 10:28:09
284
Go语言在select语句中实现优先级
select语句简介
Go语言中的Select语句用于监控和选择一组case语句来执行相应的代码。它看起来类似于switch语句,但是select语句中所有情况下的表达式都必须是通道的发送或接收操作。典型的选择使用示例如下:
选择{
case -ch1:
fmt。Println('liwenzhou.com ')
案件ch2 - 1:
fmt。Println('q1mi ')
}
Go语言中的Select关键字也可以使当前goroutine同时等待ch1可读和ch2可写。在ch1和ch2状态改变之前,select将被阻塞,直到其中一个通道变为ready状态并执行对应于case分支的代码。如果多个通道同时就绪,则随机选择一个案例执行。
除了上面展示的典型例子之外,我们还将介绍一些特殊的选择例子。
空选择
空选择意味着内部没有案例,例如:
选择{
}
空的select语句会直接阻塞当前的goro tine,使goro tine进入无法唤醒的睡眠状态。
只有一种情况
如果一个选择只包含一种情况,该选择将成为被阻止的通道读/写操作。
选择{
case -ch1:
fmt。Println('liwenzhou.com ')
}
ch1可读时会打印以上代码,否则会阻塞。
有一个默认语句
如果select还可以包含默认语句,那么当其他情况不满足时,它可以用来执行一些默认操作。
选择{
case -ch1:
fmt。Println('liwenzhou.com ')
默认值:
时间。睡眠(时间。第二)
}
ch1可读时会打印上面的代码,否则执行默认语句中的代码,相当于非阻塞通道读取操作。
摘要
选择没有任何大小写:阻止当前goroutine
Select只有一种情况:阻止发送/接收
选择有多个案例:随机选择一个符合执行条件的案例
当select中存在默认值并且不满足其他条件时:执行default语句中的代码
如何在选择中实现优先级
众所周知,当select中有多个案例时,将随机选择一个符合条件的案例执行。
现在我们有一个需求:我们有一个函数,它将从ch1和ch2连续接收任务1和任务2,
如何保证ch1和ch2同时达到就绪状态时,先执行任务1,没有任务1时再执行任务2?
Go语言程序员小明挠了挠头,写了如下函数:
func worker(ch1,ch2 -chan int,stopCh chan struct{}) {
对于{
选择{
case -stopCh:
返回
case job1 :=-ch1:
fmt。Println(job1)
默认值:
选择{
case job2 :=-ch2:
fmt。Println(作业2)
默认值:
}
}
}
}
上面的代码通过嵌套两个select来实现“优先级”,这似乎符合主题的要求。但是这个代码有问题。如果ch1和ch2都没有准备好,整个程序不会阻塞而是进入无限循环。
我该怎么办?
小明又挠了挠头,写了另一个方案:
func worker2(ch1,ch2 -chan int,stopCh chan struct{}) {
对于{
选择{
case -stopCh:
返回
case job1 :=-ch1:
fmt。Println(job1)
case job2 :=-ch2:
优先级:
对于{
选择{
case job1 :=-ch1:
fmt。Println(job1)
默认值:
中断优先级
}
}
fmt。Println(作业2)
}
}
}
这一次,小明不仅使用了嵌套选择,还使用了for循环和LABEL的组合来满足主题的要求。以上代码进入内部select循环,当外部select选择执行job2 :=-ch2时,继续尝试执行job1 :=-ch1,并始终在ch1准备好时执行,否则跳出内部select。
实际应用场景
以上需求虽然是我自己编的,但是实际生产中有实现优先选择的实际应用场景。例如,有一个在K8s控制器中实际使用上述技术的例子。这里对select中实现优先级相关代码的关键点做了补充说明,具体逻辑在此不再赘述。
//kubernetes/pkg/controller/node life cycle/scheduler/tent _ manager . go
func(TC * NoExeceetientManager)worker(worker int,done func(),stopCh -chan struct{}) {
延期完成()
//当处理具体事件的时候,我们会希望结节的更新操作优先于豆荚的更新
//因为节点更新与NoExecuteTaintManager无关应该尽快处理
//- 我们不希望用户(或系统)等到PodUpdate队列被耗尽后,才开始从受污染的结节中清除波德。
对于{
选择{
case -stopCh:
返回
案例节点更新:=-TC。node updatechannels[worker]:
tc.handleNodeUpdate(nodeUpdate)
TC。NodeUpdateQueue。完成(节点更新)
案例PodUpdate :=-TC。PodUpdatechannels[worker]:
//如果我们发现了一个豆荚需要更新,我么你需要先清空结节队列。
优先级:
对于{
选择{
案例节点更新:=-TC。node updatechannels[worker]:
tc.handleNodeUpdate(nodeUpdate)
TC。NodeUpdateQueue。完成(节点更新)
默认值:
中断优先级
}
}
//在结节队列清空后我们再处理播客更新.
tc.handlePodUpdate(podUpdate)
TC。PodUpdatequeue。完成(PodUpdate)
}
}
}
17
2022-03
28
2021-08
16
2021-06
16
2021-06
16
2021-06
16
2021-06