通过检查自开始以来经过的时间:
var i int for start := time.Now(); time.Since(start) < time.Second; { i++ }
或者使用通过调用获取的"超时"通道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++ }