英文:
For loop that breaks after n amount of seconds
问题
如何在执行后过去1秒钟后使这个简单的for
循环中断?
var i int
for {
i++
}
你可以使用time
包来实现这个目标。在每次循环迭代之后,你可以使用time.Sleep
函数来暂停1秒钟,然后使用break
语句来中断循环。
下面是修改后的代码:
import (
"time"
)
var i int
for {
i++
time.Sleep(1 * time.Second)
break
}
这样,循环将在执行后的1秒钟后中断。
英文:
How can I make this simple for
loop break after exactly one 1s has passed since its execution?
var i int
for {
i++
}
答案1
得分: 60
通过检查从开始到现在的经过时间:
var i int
for start := time.Now(); time.Since(start) < time.Second; {
i++
}
或者使用一个"timeout"通道,通过调用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 { // 每16次迭代检查一次
if time.Since(start) > time.Second {
break
}
}
i++
}
我们还可以一次计算出结束时间(循环必须结束的时间),然后只需将当前时间与其进行比较:
var i int
for end := time.Now().Add(time.Second); ; {
if i&0x0f == 0 { // 每16次迭代检查一次
if time.Now().After(end) {
break
}
}
i++
}
英文:
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++
}
答案2
得分: 15
我知道这个问题有点旧,但以下内容对于寻找类似场景的人可能有用:
func keepCheckingSomething() (bool, error) {
timeout := time.NewTimer(10 * time.Second)
ticker := time.NewTicker(500 * time.Millisecond)
defer timeout.Stop()
defer ticker.Stop()
// 不断尝试,直到超时或获得结果/错误
for {
select {
// 超时!返回超时错误
case <-timeout.C:
// 可能最后再检查一次
ok, err := checkSomething()
if !ok {
return false, errors.New("超时")
}
return ok, err
// 定时器滴答,我们应该检查 checkSomething()
case <-ticker.C:
ok, err := checkSomething()
if err != nil {
// 我们可以返回,或者忽略错误
return false, err
// checkSomething() 完成!返回结果
} else if ok {
return true, nil
}
// checkSomething() 还没有完成,但也没有失败,让我们再试一次
}
}
}
希望对你有帮助!
英文:
I know the question is a bit old, but below might be useful for someone looking for similar scenario:
func keepCheckingSomething() (bool, error) {
timeout := time.NewTimer(10 * time.Second)
ticker := time.NewTicker(500 * time.Millisecond)
defer timeout.Stop()
defer ticker.Stop()
// Keep trying until we're timed out or get a result/error
for {
select {
// Got a timeout! fail with a timeout error
case <-timeout:
// maybe, check for one last time
ok, err := checkSomething()
if !ok {
return false, errors.New("timed out")
}
return ok, err
// 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
}
}
}
答案3
得分: 0
var i int
responseTimeout = 1 * time.Minute
deadline := time.Now().Add(responseTimeout)
for time.Now().Before(deadline) {
i++
}
var i int
responseTimeout = 1 * time.Minute
deadline := time.Now().Add(responseTimeout)
for time.Now().Before(deadline) {
i++
}
这段代码是使用Go语言编写的。它声明了一个整数变量i,并设置了一个响应超时时间为1分钟。然后,它使用当前时间加上超时时间来计算截止时间。接下来,它进入一个循环,只要当前时间在截止时间之前,就会不断地增加i的值。
英文:
var i int
responseTimeout = 1 * time.Minute
deadline := time.Now().Add(responseTimeout)
for time.Now().Before(deadline) {
i++
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论