Python loop to run for certain amount of seconds
Asked Answered
C

7

77

I have a while loop, and I want it to keep running through for 15 minutes. it is currently:

while True:
    #blah blah blah

(this runs through, and then restarts. I need it to continue doing this except after 15 minutes it exits the loop)

Thanks!

Commutual answered 23/6, 2014 at 20:17 Comment(0)
S
160

Try this:

import time

t_end = time.time() + 60 * 15
while time.time() < t_end:
    # do whatever you do

This will run for 15 min x 60 s = 900 seconds.

Function time.time returns the current time in seconds since 1st Jan 1970. The value is in floating point, so you can even use it with sub-second precision. In the beginning the value t_end is calculated to be "now" + 15 minutes. The loop will run until the current time exceeds this preset ending time.

Seed answered 23/6, 2014 at 20:34 Comment(7)
Thanks I tested it out originally with just 60 seconds and it stopped so I know that 15 minutes will work too.Commutual
Another question: does the following syntax work? if keys[pygame.K_LEFT]: answer = "left" f = open("answer.rtf", "a") f.write(answer) f.close() It won't let me open up the textfile after, I'm wondering if I'm doing something wrong or if my computer is messing up.Commutual
Finding slight syntax errors in code is very difficult from the SO comments, so maybe you should create another question. However, at least the if operation is wrong, there should be == instead of =, and the colon should be after "left". If you cannot make it work with reasonable effort, post another question. (Just make sure you do not do anything wrong with indentation.)Seed
@oam811: use time.monotonic() on Python 3, to avoid unexpected delays due to machine clock adjustments (time.time() can be set back).Rectal
Is there a way to have it notify me if it had to skip a loop due to the time constraint?Lindo
this doesn't work when I have a for loop under the while loop. Is there a way to control that (especially if user input is required)? ie: while time.monotonic()<T_end: for i in range(100): input("answer to some question")Carolus
for year 2021 , I have tried this code, it works with Python 3.8 but you do not need multiply 60 to get the seconds.Antitrades
H
12

If I understand you, you can do it with a datetime.timedelta -

import datetime

endTime = datetime.datetime.now() + datetime.timedelta(minutes=15)
while True:
  if datetime.datetime.now() >= endTime:
    break
  # Blah
  # Blah
Hanser answered 23/6, 2014 at 20:35 Comment(7)
Thanks it worked, but I'm using DrV's answer just because it makes more sense to me.Commutual
@Elliott, Is there any reason you didn't use a now() < endTime comparison directly in the while statement instead of using a break?Vullo
@Bob To match up with OP's question.Hanser
while True: infinite loop with break clause is more pythonic than the accepted answerLuminiferous
@Luminiferous can you please explain why it is more pythonic? To my mind, while with a direct condition is simpler and clearer. In addition it is more consistent with list comprehensions, etc, in that it does not go into nested code.Deuteron
@Deuteron The expression while True: is considered more Pythonic because it adheres to the Python philosophy of simplicity and readability. while True: is easier to understand at first glance. It's clear that this is an infinite loop that will continue until it's explicitly broken. On the other hand, while time.time() < t_end: requires the reader to understand the time.time() function and the t_end variable. It doesn't depend on the time module or any other specific conditions.Luminiferous
@Deuteron if you have not yet, try running import thisLuminiferous
F
4
import time
delay = 60*15 # For 15 minutes delay 
close_time = time.time()+delay
while True:
    # ...
    if time.time() > close_time:
        break
Fulviah answered 10/10, 2017 at 19:54 Comment(1)
Or even more simply while close_time>time.time(): without the need for if time.time()>close_time: break...Admissible
D
3

I was looking for an easier-to-read time-loop when I encountered this question here. Something like:

for sec in max_seconds(10):
      do_something()

So I created this helper:

# allow easy time-boxing: 'for sec in max_seconds(42): do_something()'
def max_seconds(max_seconds, *, interval=1):
    interval = int(interval)
    start_time = time.time()
    end_time = start_time + max_seconds
    yield 0
    while time.time() < end_time:
        if interval > 0:
            next_time = start_time
            while next_time < time.time():
                next_time += interval
            time.sleep(int(round(next_time - time.time())))
        yield int(round(time.time() - start_time))
        if int(round(time.time() + interval)) > int(round(end_time)): 
            return

It only works with full seconds which was OK for my use-case.

Examples:

for sec in max_seconds(10) # -> 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
for sec in max_seconds(10, interval=3) # -> 0, 3, 6, 9
for sec in max_seconds(7): sleep(1.5) # -> 0, 2, 4, 6
for sec in max_seconds(8): sleep(1.5) # -> 0, 2, 4, 6, 8

Be aware that interval isn't that accurate, as I only wait full seconds (sleep never was any good for me with times < 1 sec). So if your job takes 500 ms and you ask for an interval of 1 sec, you'll get called at: 0, 500ms, 2000ms, 2500ms, 4000ms and so on. One could fix this by measuring time in a loop rather than sleep() ...

Daron answered 1/2, 2018 at 12:34 Comment(0)
D
3

For those using asyncio, an easy way is to use asyncio.wait_for():

async def my_loop():
    res = False
    while not res:
        res = await do_something()

await asyncio.wait_for(my_loop(), 10)
Dong answered 29/3, 2020 at 16:32 Comment(0)
C
0

The best solution for best performance is to use @DrV answer and the suggestion from @jfs to use time.monotonic():

    import time
    from datetime import datetime, timedelta

    count = 0
    end_time = time.monotonic() + 10
    while time.monotonic() < end_time:
        count += 1
    print(f'10 second result: {count=:,}')
    # 10 second result: count=185,519,745

    count = 0
    end_time = time.time() + 10
    while time.time() < end_time:
        count += 1
    print(f'10 second result: {count=:,}')
    # 10 second result: count=158,219,172

    count = 0
    end_time = datetime.now() + timedelta(seconds=10)
    while datetime.now() < end_time:
        count += 1
    print(f'10 second result: {count=:,}')
    # 10 second result: count=39,168,578
Commutative answered 12/11, 2022 at 8:18 Comment(0)
A
-4

try this:

import time
import os

n = 0
for x in range(10): #enter your value here
    print(n)
    time.sleep(1) #to wait a second
    os.system('cls') #to clear previous number
                     #use ('clear') if you are using linux or mac!
    n = n + 1
Archespore answered 26/7, 2017 at 23:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.