对于在n秒之后中断的循环

时间:2017-01-19 09:54:20

标签: for-loop go timeout

如何在执行完一个1s之后才能进行这个简单的for循环中断?

var i int

for {
  i++
}

2 个答案:

答案 0 :(得分:21)

通过检查自开始以来经过的时间:

var i int
for start := time.Now(); time.Since(start) < time.Second; {
    i++
}

或使用&#34;超时&#34;通过调用time.After()获得的频道。使用select检查时间是否已到,但您必须添加default分支,以便进行非阻止检查。如果时间到了,请从循环中断开。同样非常重要的是使用标签并从for循环中断,否则break将从select中脱离,这将是无限循环。

loop:
    for timeout := time.After(time.Second); ; {
        select {
        case <-timeout:
            break loop
        default:
        }
        i++
    }

注意:如果循环体还执行通信操作(如发送或接收),则使用超时通道可能是唯一可行的选项! (您可以在同一select列出超时检查和循环通信操作。)

我们可能会重写超时通道解决方案,不使用标签:

for stay, timeout := true, time.After(time.Second); stay; {
    i++
    select {
    case <-timeout:
        stay = false
    default:
    }
}

优化

我知道你的循环只是一个例子,但如果循环只做了一点点工作,那么在每次迭代中都不值得检查超时。我们可能会重写第一个检查超时的解决方案,例如在每10次这样的迭代中:

var i int
for start := time.Now(); ; {
    if i % 10 == 0 {
        if time.Since(start) > time.Second {
            break
        }
    }
    i++
}

我们可以选择一个2的倍数的迭代次数,然后我们可以使用比剩余检查更快的位掩码:

var i int
for start := time.Now(); ; {
    if i&0x0f == 0 { // Check in every 16th iteration
        if time.Since(start) > time.Second {
            break
        }
    }
    i++
}

我们也可以计算一次结束时间(当循环必须结束时),然后你只需要比较当前时间:

var i int
for end := time.Now().Add(time.Second); ; {
    if i&0x0f == 0 { // Check in every 16th iteration
        if time.Now().After(end) {
            break
        }
    }
    i++
}

答案 1 :(得分:0)

我知道这个问题有点老了,但是下面的内容对于寻找类似情况的人可能有用:

func keepCheckingSomething() (bool, error) {
    timeout := time.After(10 * time.Second)
    ticker := time.Tick(500 * time.Millisecond)
    // Keep trying until we're time out or get a result or get an error
    for {
        select {
        // Got a timeout! fail with a timeout error
        case <-timeout:
            return false, errors.New("timed out")
        // Got a tick, we should check on checkSomething()
        case <-ticker:
            ok, err := checkSomething()
            if err != nil {
            // We may return, or ignore the error
                return false, err
            // checkSomething() done! let's return
            } else if ok {
                return true, nil
            }
            // checkSomething() isn't done yet, but it didn't fail either, let's try again
        }
    }
}