基于秒数退出 Golang 循环

huangapple go评论82阅读模式
英文:

Golang exit a loop based on seconds

问题

我正在尝试在循环中执行SQL查询,循环需要在经过5秒后退出,同时如果迭代完成也需要退出。

startTime := time.Now()
for _, index := range indices {
    elapsedTime := time.Since(startTime)

    if elapsedTime.Seconds() >= 5 {
        break
    }
    // 执行SQL查询
} 

是否有更好的方法来实现这个功能?

英文:

I'm trying to execute sql query in a loop and the loop needs to exit 5 seconds is elapsed and also need to exit, if the iteration is complete.

startTime := time.Now()
	for _, index := range indices {
		elapsedTime := time.Since(startTime)

		if elapsedTime.Seconds() >= 5 {
			break
		}
		// sql query execution
	} 

is there any better approach for this?

答案1

得分: 2

忽略一下这里明显存在的X-Y问题,在5秒后跳出循环是很简单的:

你可以使用一个时间间隔和一个select来实现这样的功能:

timer := time.NewTimer(5 * time.Second)
defer timer.Stop() // 总是要清理
for _, i := range indeces {
    select {
    case <-timer.C():
        // 计时器已经过期
        return // 完成
    default:
       // 做你想要循环做的事情
    }
}

很简单。为了确保在5秒时间段过去后不再执行查询,你还可以使用带有超时的上下文,并将该上下文传递给所有与SQL相关的调用:

ctx, cfunc := context.WithTimeout(context.Background(), 5 * time.Second)
defer cfunc() // 同样,总是要清理

循环的其余部分看起来基本相同:

for _, i := range indeces {
    select {
    case <-ctx.Done():
        return
    default:
       // 做其他事情
    }
}

X-Y问题

现在回到这里的X-Y问题:我不确定设置一个硬时间限制是否是解决你问题的方法。为什么你要迭代一个名为"indeces"的切片,这将导致在一个较长的时间段内执行任意数量的查询,并且正如你在评论中提到的,为什么所有这些查询都不同?这个循环应该做什么?你想要实现什么?几乎可以确定的是,你所面临的问题不应该被解决,而是可以很容易地避免(因此,你问如何做Y,而真正的问题是你为什么要做X,导致你现在寻找做Y的方法)。

英文:

Ignoring for a second the apparent X-Y problem at play here, breaking out of a loop after 5 seconds is trivial to do:

You can just use a time interval and a select for something like this:

timer := time.NewTimer(5 * time.Second)
defer timer.Stop() // always clean up
for _, i := range indeces {
    select {
    case &lt;-timer.C():
        // timer has expired
        return // done
    default:
       // do whatever you want the loop to do
    }
}

Easy. To ensure queries aren't executed after the 5 second period has elapsed, you can also use a context with timeout, and pass said context to all SQL related calls:

ctx, cfunc := context.WithTimeout(context.Background(), 5 * time.Second)
defer cfunc() // again, always clean up after yourself

The rest of the loop will look pretty much the same:

for _, i := range indeces {
    select {
    case &lt;-ctx.Done():
        return
    default:
       // do whatever
    }
}

X-Y problem

Now circling back to the X-Y problem here: I'm not sure whether implementing a hard time limit is the solution to your problem. Why are you iterating over a slice named "indeces", which in turn results in an arbitrary number of queries being executed over an extended period of time, and, as you mentioned in comments, why are all these queries different to begin with? What is this loop supposed to do? What are you trying to implement. There's a close to 100% guarantee that what you have is a problem that shouldn't be solved, but instead can be easily avoided (hence, you're asking how do to Y, whereas the real question is why you did X that causes you to now looking for a way to do Y)

答案2

得分: 0

你是在询问类似于在5秒后超时的上下文中使用的内容吗?根据你的实现方式,你可以将上下文传递给你的SQL查询函数,或者在上下文超时时直接从例程中返回。一个大致的概述可能如下所示。

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

_, err := db.ExecContext(ctx, "SELECT ...")
英文:

Are you asking about something like using a context that times out after 5 seconds? Depending on your implementation, you could pass the context to your sql query func or simply return from the routine when the context times out. A rough outline might look something like this.

ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

_, err := db.ExecContext(ctx, &quot;SELECT ...&quot;)

huangapple
  • 本文由 发表于 2023年3月24日 13:04:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75830198.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定