douji2283 2017-01-19 09:54
浏览 29
已采纳

for循环在n秒后中断

How can I make this simple for loop break after exactly one 1s has passed since its execution?

var i int

for {
  i++
}
  • 写回答

2条回答 默认 最新

  • dongyiba8082 2017-01-19 09:57
    关注

    By checking the elapsed time since the start:

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

    Or using a "timeout" channel, acquired by calling time.After(). Use select to check if time is up, but you must add a default branch so it will be a non-blocking check. If time is up, break from the loop. Also very important to use a label and break from the for loop, else break will just break from the select and it will be an endless loop.

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

    Note: If the loop body also performs communication operations (like send or receive), using a timeout channel may be the only viable option! (You can list the timeout check and the loop's communication op in the same select.)

    We may rewrite the timeout channel solution to not use a label:

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

    Optimization

    I know your loop is just an example, but if the loop is doing just a tiny bit of work, it is not worth checking the timeout in every iteration. We may rewrite the first solution to check timeout e.g. in every 10 iterations like this:

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

    We may choose an iteration number which is a multiple of 2, and then we may use bitmasks which is supposed to be even faster than remainder check:

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

    We may also calculate the end time once (when the loop must end), and then you just have to compare the current time to this:

    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条)

报告相同问题?

悬赏问题

  • ¥15 powerbuilder中的datawindow数据整合到新的DataWindow
  • ¥20 有人知道这种图怎么画吗?
  • ¥15 pyqt6如何引用qrc文件加载里面的的资源
  • ¥15 安卓JNI项目使用lua上的问题
  • ¥20 RL+GNN解决人员排班问题时梯度消失
  • ¥15 使用LM2596制作降压电路,一个能运行,一个不能
  • ¥60 要数控稳压电源测试数据
  • ¥15 能帮我写下这个编程吗
  • ¥15 ikuai客户端l2tp协议链接报终止15信号和无法将p.p.p6转换为我的l2tp线路
  • ¥15 phython读取excel表格报错 ^7个 SyntaxError: invalid syntax 语句报错