18910140161

Go语言在select语句中实现优先级

顺晟科技

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)

}

}

}

相关文章
我们已经准备好了,你呢?
2024我们与您携手共赢,为您的企业形象保驾护航