0

I want to run a function at the start of every minute, without it lagging over time. Using time.sleep(60) eventually lags.

while True:
now = datetime.datetime.now().second
if now == 0:
    print(datetime.datetime.now())

The function doesn't take a minute to run so as long as it runs a the beginning it should be fine, I'm not sure if this code is resource-efficient, as its checking every millisecond or so and even if it drifts the if function should correct it.

  • 7
    Why not use a cron job? And leave the timing to your OS. – Robby Cornelissen Mar 19 '20 at 09:33
  • 1
    Does this answer your question? [What is the best way to repeatedly execute a function every x seconds?](https://stackoverflow.com/questions/474528/what-is-the-best-way-to-repeatedly-execute-a-function-every-x-seconds) – Georgy Mar 19 '20 at 10:22

2 Answers2

2

Repeat scheduling shouldn't really be done in python, especially by using time.sleep. The best way would be to get your OS to schedule running the script, using something like cron if you're on Linux or Task Scheduler if you're on Windows

KJTHoward
  • 806
  • 4
  • 16
1

Assuming that you've examined and discarded operating-based solutions such as cron or Windows Scheduled Tasks, what you suggest will work but you're right in that it's CPU intensive. You would be better off sleeping for one second after each check so that:

  1. It's less resource intensive; and, more importantly
  2. It doesn't execute multiple times per at the start of each minute if the job takes less than a second.

In fact, you could sleep for even longer immediately after the payload by checking how long to the next minute, and use the minute to decide in case the sleep takes you into a second that isn't zero. Something like this may be a good start:

# Ensure we do it quickly first time.

lastMinute = datetime.datetime.now().minute - 1

# Loop forever.

while True:
    # Get current time, do payload if new minute.

    thisTime = datetime.datetime.now()
    if thisTime.minute != lastMinute:
        doPayload()
        lastMinute = thisTime.minute

        # Try to get close to hh:mm:55 (slow mode).
        # If payload took more than 55s, just go
        # straight to fast mode.

        afterTime = datetime.datetime.now()
        if afterTime.minute == thisTime.minute:
            if afterTime.second < 55:
                time.sleep (55 - afterTime.second)

    # After hh:mm:55, check every second (fast mode).

    time.sleep(1)
paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953