简体   繁体   English

几分钟后如何打破while循环?

[英]How to break a while loop after some minutes?

I have a while loop in my python program and I want to break from this loop after 5 minutes, I'm currently using the following code:我的 python 程序中有一个 while 循环,我想在 5 分钟后break这个循环,我目前正在使用以下代码:

start_time = time.time()
while time.time() - start_time < 300:
    # do something

However, it takes added time in each iteration to calculate the time.time() - start_time < 300: part.但是,每次迭代都需要额外的时间来计算time.time() - start_time < 300:部分。 For example, if I use a for loop with 30000 iterations and it lasts 5 minutes, the above code does fewer iterations than that.例如,如果我使用具有 30000 次迭代的for循环并持续 5 分钟,则上述代码执行的迭代次数少于此次数。

What should I do about it?我该怎么办? I have to break the loop after 5 minutes and I just want to handle this by time, not by for loop iterations.我必须在 5 分钟后中断循环,我只想按时间处理这个问题,而不是通过for循环迭代。

One of my friends suggested datetime package, but I do not know how it works.我的一位朋友建议使用datetime包,但我不知道它是如何工作的。

the above code does fewer iterations than that.上面的代码执行的迭代次数比这少。

A likely reason is that checking the time itself takes time.一个可能的原因是检查时间本身需要时间。 Therefore, you could check the time less often:因此,您可以不那么频繁地检查时间:

start_time = time.time()
lv = 0
while True:
    if lv == 100: # check time only once in 100 iterations
        if time.time() - start_time > 300:
            break
        else:
            lv = 0

    # do something

    lv +=1

It sounds like need of implementing timeout for me.听起来需要为我实现超时。 You might use built-in threading module to do it following way:您可以使用内置threading模块按以下方式执行此操作:

import time
from threading import Thread, Event

stop = Event()

def function():
    while not stop.is_set():
        print('*')
        time.sleep(1)

thread = Thread(target=function)

thread.start()
thread.join(timeout=60)
stop.set()

Above code simply prints * every second for 60 seconds.上面的代码只是每秒打印* 60秒。

I think using threading and sleep is the best approach.我认为使用线程和睡眠是最好的方法。 You can do it in a simple way using a lambda function to create a sleeping background thread and simply check if if the thread is still running inside your loop (break the loop when time is up):您可以使用 lambda 函数以一种简单的方式来创建一个休眠的后台线程,并简单地检查该线程是否仍在您的循环中运行(时间到时中断循环):

from threading import Thread
from time import sleep

fiveMinutes = Thread(target=lambda:sleep(300)) # 5 min sleeping thread (300 seconds)
fiveMinutes.start() # start wait time

for i in range(10**10): # <-- this represents your loop condition
    # ...
    if not fiveMinutes.is_alive(): break # break after 5 minutes elapsed
    # ...

This should add less overhead to your processing loop so the timed out iterations should be very close to the effective time to process the same number of iterations.这应该会为您的处理循环增加更少的开销,因此超时迭代应该非常接近处理相同迭代次数的有效时间。

[EDIT] Thread/sleep vs time.time() [编辑] 线程/睡眠 vs time.time()

I made a few more tests and there is very little difference between using the sleeping thread and an optimal use of the time() function.我做了一些更多的测试,使用休眠线程和最佳使用 time() 函数之间几乎没有区别。 The overhead is less than a microsecond per iteration:每次迭代的开销小于一微秒:

from time import time

fiveMinutes = time() + 300

for i in range(10**10): # <-- this represents your loop condition
    # ...
    if time() > fiveMinutes : break # break after 5 minutes elapsed
    # ...

If you are getting a 3 seconds difference over a 1 minute sample, I would suspect that the processing time of your logic has its own variability (ie running the same number of iterations in a loop will vary from one run to the next).如果您在 1 分钟的样本中得到 3 秒的差异,我会怀疑您的逻辑的处理时间有其自身的可变性(即在循环中运行相同数量的迭代会因一次运行而异)。 Either that or you are checking for timeout a lot more often than the 11,311 iterations would suggest (perhaps by checking inside a nested loop).要么是这样,要么您检查超时的次数比 11,311 次迭代建议的次数要多得多(可能通过检查嵌套循环)。 In my tests the two approaches varied by less than 0.5 second over a 60 second sample executing 41,000 iterations: +0.37sec for time() and +0.23sec for thread.在我的测试中,在执​​行 41,000 次迭代的 60 秒样本中,两种方法的变化不到 0.5 秒:time() 为 +0.37 秒,线程为 +0.23 秒。

(a bit of tinkering later, I think I broadly agree with Alain. I get a significant speed up from just breaking after a certain number of iterations, but whether using a thread, time.time directly or a partial sampling approach, pretty much all of them end up degrading loop time. time.time() itself is probably already fairly highly optimized, so all the extra booleans and stuff to avoid using it too much probably don't improve things much). (稍后稍作修改,我想我大致同意 Alain。经过一定次数的迭代后,我从中断中获得了显着的加速,但是无论是直接使用线程、time.time 还是部分采样方法,几乎​​所有其中一些最终会降低循环时间time.time()本身可能已经相当高度优化,所以所有额外的布尔值和避免使用太多的东西可能不会改善太多)。

Don't know if it's more efficient, but you could try a thread and a shared mutable object to drive the loop.不知道它是否更有效,但您可以尝试一个线程和一个共享的可变对象来驱动循环。 Here's a test at 0.5 seconds.这是 0.5 秒的测试。

import time
from threading import Thread

def myfunc(mutable_):
    time.sleep(0.5)
    mutable_.value = False
    print("done")


class Mutable:
    value = True

mutable_ = Mutable()

t = Thread(target=myfunc, args=(mutable_,))

start = time.time()
t.start()
while mutable_.value:
    print(time.time() - start)

The unknown here to me is whether the loop's attribute access to mutable_.value , which doesn't need to involve the thread directly is that much cheaper than polling the thread itself.我不知道的是,循环对mutable_.value的属性访问(不需要直接涉及线程)是否比轮询线程本身便宜得多。

Now, in my test, there was a bit of a difference where the thread had not yet updated the value so the loop ran a bit over compared to using own local time check.现在,在我的测试中,在线程尚未更新值的情况下存在一些差异,因此与使用自己的本地时间检查相比,循环运行了一点。 Might be possible to set your thread time out at 299.9 seconds, get close and finish more carefully.可能可以将您的线程超时设置为 299.9 秒,靠近并更仔细地完成。

Here's a v2 using thread sleeping to get most of the way there (that 0.49) and a, normally short-circuited time.time() check to finalize.这是一个 v2 使用线程睡眠来获得大部分方式(即 0.49)和一个通常短路的time.time()检查以完成。

def myfunc(mutable_, looptime):
    time.sleep(looptime)
    mutable_.value = False

t = Thread(target=myfunc, args=(mutable_,.49))

t.start()
start = time.time()

while mutable_.value or (time.time() - start <= .5):
    print(time.time() - start)

Try this following:试试这个:

start_time = time.time() + 300
while True:
    if time.time() > start_time:
         break

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM