select超时优先级

LovesAsuna · 2021-05-25 19:45:02 · 3520 次点击 · 大约8小时之前 开始浏览    置顶
这是一个创建于 2021-05-25 19:45:02 的主题,其中的信息可能已经有所发展或是发生改变。

select中的超时优先级

select中可以通过在case设置time.After进行超时,但为什么超时操作会比其他的case优先级低?如果其他的case会运行那么超时就不作数。为此我在主协程模拟了一个超时

func main() {
    channel := make(chan interface{}, 100)
    delay := make(chan interface{})
    for i := 0; i < 10; i++ {
        channel <- 1
    }
    go func() {
        for {
            select {
            case <-delay:
                fmt.Println("超时")
            case i := <-channel:
                fmt.Println(i)
                time.Sleep(time.Second)
            }
        }
    }()
    time.After(3 * time.Second)
    delay <- 1
    for {

    }
}

结果打印如下

1
超时
1
1
1
1
1
1
  • 这样的结果很符合我对"超时"的认知,函数的超时只取决于调用者本身而不是取决于函数中的状态。

而正常的select却不是这样的,我做了这样的对比只是印证了time.After内部的实现原理与我写的不一样

查看源码可以发现time.After实际上是调用了NewTimer,NewTimer的源码是这样的

func NewTimer(d Duration) *Timer {
    c := make(chan Time, 1)
    t := &Timer{
        C: c,
        r: runtimeTimer{
            when: when(d),
            f:    sendTime,
            arg:  c,
        },
    }
    startTimer(&t.r)
    return t
}
  • 可以看出time.After其实是返回了NewTimer内部定义的Timer的C。

  • 而我认为问题的关键就在于下面的startTimer,其中肯定有往C输入内容的管道。往C输入内容的时机就是问题的答案。

  • 由于源码过于复杂比较难分析,因此想问问这个优先级的原因出在哪里?


有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

3520 次点击  
加入收藏 微博
4 回复  |  直到 2021-07-02 11:52:22
xfdbs
xfdbs · #1 · 4年之前

我认为你的代码有2点问题: 第一,你的3秒超时效果并没有达到, 正确的用法是tc := time.After(time.Second * 3); <-tc;delay <- 1 第二, select那里, delay和channel都有数据的时候,select是随机选择一个执行,而不保证delay优先执行。你的channel是提前放入10个数据,实际运行的结果是不能保证到了超时就能打印“超时”

jarlyyn
jarlyyn · #2 · 4年之前

你的代码我愣是没看懂……

正常for中的select至少会有个分支进行return,以退出这个处理循环。

如果你要超时后不继续读数据的话

至少应该是

    go func() {
        for {
            select {
            case <-delay:
                fmt.Println("超时")
                return
            case i := <-channel:
                fmt.Println(i)
                time.Sleep(time.Second)
            }
        }
    }()
__Golang__
__Golang__ · #3 · 4年之前

不存在优先级吧,select 多个 case 同时满足的话,会随机触发一个

harman
harman · #4 · 4年之前
xfdbsxfdbs #1 回复

我认为你的代码有2点问题: 第一,你的3秒超时效果并没有达到, 正确的用法是`tc := time.After(time.Second * 3); <-tc;delay <- 1` 第二, select那里, delay和channel都有数据的时候,select是随机选择一个执行,而不保证delay优先执行。你的channel是提前放入10个数据,实际运行的结果是不能保证到了超时就能打印“超时”

正解,估计这楼主没怎么看select的说明文档,time.After也整了个寂寞。。。

添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传