登录
首页 >  Golang >  Go问答

go select语句的强制优先级

来源:Golang技术栈

时间:2023-04-14 10:07:02 204浏览 收藏

大家好,我们又见面了啊~本文《go select语句的强制优先级》的内容中将会涉及到golang等等。如果你正在学习Golang相关知识,欢迎关注我,以后会给大家带来更多Golang相关文章,希望我们能一起进步!下面就开始本文的正式内容~

问题内容

我有以下代码:

func sendRegularHeartbeats(ctx context.Context) {
    for {
        select {
        case 

这个函数在一个专门的 go-routine 中执行,并且每秒发送一个心跳消息。当上下文被取消时,整个过程应该立即停止。

现在考虑以下场景:

ctx, cancel := context.WithCancel(context.Background())
cancel()
go sendRegularHeartbeats(ctx)

这会以封闭的上下文启动心跳例程。在这种情况下,我不希望传输任何心跳。所以case应该立即输入选择中的第一个块。

但是,似乎case无法保证评估块的顺序,并且代码有时会发送心跳消息,即使上下文已经取消。

实现这种行为的正确方法是什么?

我可以在第二个中添加一个“isContextclosed”-check case,但这看起来更像是一个丑陋的解决方法。

正确答案

提前注意:

您的示例将按照您的预期工作,就好像上下文在sendRegularHeartbeats()被调用时已经被取消一样,case 通信将是唯一准备好继续并因此被选中的通信。另一个case 只会 在 1 秒后 准备好继续,所以一开始不会选择它。但是要在可能准备好多个案例时明确处理优先级,请继续阅读。


语句case的分支(评估顺序是它们列出的顺序)不同,语句的分支中没有优先级或任何顺序保证。switchcaseselect

引用规范:选择语句:

如果一个或多个通信可以进行, 则通过统一的伪随机选择选择一个可以进行 的通信。否则,如果存在默认情况,则选择该情况。如果没有默认情况,“select”语句会阻塞,直到至少有一个通信可以继续。

如果可以进行更多通信,则随机选择一个。时期。

如果您想保持优先级,您必须自己(手动)执行此操作。您可以使用多个语句(后续的,不是嵌套的)来执行此操作,在 较早select的中列出具有更高优先级的语句,如果这些语句还没有准备好继续进行,请务必添加一个分支以避免阻塞。您的示例需要 2 个语句,第一个检查是您想要更高优先级的语句。 __select``default``select``

我还建议使用单个而不是在每次迭代time.Ticker中调用(也在引擎盖下使用 a,但它不会重用它,只是“将其丢弃”并在下一次调用时创建一个新的)。time.After()time.After()``time.Ticker

这是一个示例实现:

func sendRegularHeartbeats(ctx context.Context) {
    ticker := time.NewTicker(time.Second)
    defer ticker.Stop()

    for {
        select {
        case 

如果上下文在被调用时已经被取消,这将不会发送任何心跳,因为您可以在Go PlaygroundsendRegularHeartbeats()上检查/验证它。

如果您将cancel()呼叫延迟 2.5 秒,则将发送 2 个心跳:

ctx, cancel := context.WithCancel(context.Background())
go sendRegularHeartbeats(ctx)
time.Sleep(time.Millisecond * 2500)
cancel()
time.Sleep(time.Second * 2)

在Go Playground上试试这个。

到这里,我们也就讲完了《go select语句的强制优先级》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于golang的知识点!

声明:本文转载于:Golang技术栈 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>