doutan1637 2018-11-09 02:32
浏览 70
已采纳

当选择组中的任何通道在指定时间内没有收到信号时,中断跳出环路

How do I break out of the idiomatic Go for loop containing select statement, if and only if I receive no signals on any of the channels my select statement is listening to, for a particular period of time.

Let me enhance the question with an example.

Setup:

  1. Lets say that i have a channel var listenCh <-chan string that I am listening to.
  2. Let us assume that some other go routine(not in our control) sends different strings on this channel.
  3. I do some processing with the given string and then listen for the next string on the listenCh.

Requirement:

I want to wait 10 seconds maximum(precision not critical), between two successive signals on the listenCh, before I shut down my operations(break out of for loop permanently).

Code Stub:

func doingSomething(listenCh <-chan string) {
  var mystr string
  for {
    select {
      case mystr <-listenCh:
        //dosomething
      case /*more than 10 seconds since last signal on listenCh*/:
        return
    }
  }
}

How would I achieve my requirement in the most efficient manner possible.

The usual quit channel technique with time.After(time.Duration) seems to not reset after one loop and hence the whole program closes in 10 seconds even if there is a continuous stream of values.

I find variants of the question(but not what I want) on SO, but none that I saw answers my particular use case.

  • 写回答

1条回答 默认 最新

  • douyan0732 2018-11-09 02:47
    关注

    Foreword: Using time.Timer is the recommended way, use of time.After() here is only for demonstration and reasoning. Please use the 2nd approach.


    Using time.After() (not recommended for this)

    If you put time.After() in the case branch, that will "reset" in each iteration, because that will return you a new channel each time, so that works:

    func doingSomething(listenCh <-chan string) {
        for {
            select {
            case mystr := <-listenCh:
                log.Println("Received", mystr)
            case <-time.After(1 * time.Second):
                log.Println("Timeout")
                return
            }
        }
    }
    

    (I used 1 second timeout for testability on the Go Playground.)

    We can test it like:

    ch := make(chan string)
    go func() {
        for i := 0; i < 3; i++ {
            ch <- fmt.Sprint(i)
            time.Sleep(500 * time.Millisecond)
        }
    }()
    doingSomething(ch)
    

    Output (try it on the Go Playground):

    2009/11/10 23:00:00 Received 0
    2009/11/10 23:00:00 Received 1
    2009/11/10 23:00:01 Received 2
    2009/11/10 23:00:02 Timeout
    

    Using time.Timer (recommended solution)

    If there is a high rate receiving from the channel, this might be a bit of wasting resources, as a new timer is created and used under the hood by time.After(), which doesn't magically stop and get garbage collected immediately when it's not needed anymore in case you receive a value from the channel before timeout.

    A more resource-friendly solution would be to create a time.Timer before the loop, and reset it if a value is received before a timeout.

    This is how it would look like:

    func doingSomething(listenCh <-chan string) {
        d := 1 * time.Second
        t := time.NewTimer(d)
        for {
            select {
            case mystr := <-listenCh:
                log.Println("Received", mystr)
                if !t.Stop() {
                    <-t.C
                }
                t.Reset(d)
            case <-t.C:
                log.Println("Timeout")
                return
            }
        }
    }
    

    Testing and output is the same. Try this one on the Go Playground.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 全部备份安卓app数据包括密码,可以复制到另一手机上运行
  • ¥15 Python3.5 相关代码写作
  • ¥20 测距传感器数据手册i2c
  • ¥15 RPA正常跑,cmd输入cookies跑不出来
  • ¥15 求帮我调试一下freefem代码
  • ¥15 matlab代码解决,怎么运行
  • ¥15 R语言Rstudio突然无法启动
  • ¥15 关于#matlab#的问题:提取2个图像的变量作为另外一个图像像元的移动量,计算新的位置创建新的图像并提取第二个图像的变量到新的图像
  • ¥15 改算法,照着压缩包里边,参考其他代码封装的格式 写到main函数里
  • ¥15 用windows做服务的同志有吗