How to program a task with a timer in my Python code?

Question:

I want to execute a task after certain time, so I have tried a countdown timer with a condition of being finished (when countdown variable = 0, the task is performed). The thing is that I don’t want to stop the execution of the main program while performing the countdown. I have tried this:

import time

def countdown(num_of_secs):
    while(num_of_secs):
        time.sleep(1)
        num_of_secs -= 1
        return num_of_secs

So, I run my code setting a number of seconds to the countdown, and when this countdown reaches the 0 value, a task must be executed. Using this code (it uses a while), when I call my function "countdown" it stops the execution of the main program, so it is the same as a big time.sleep. I want to carry out this countdown in the background, without stopping other actions until the countdown finishes and the task starts.
Thank you

Answers:

Usually python only has a single program flow, so every instruction needs to complete before the next one can get executed.

For your case you need asynchronicity, with e.g. asyncio.sleep(5) as a separate task in the same event loop.

import asyncio

async def sleeper():
    print('Holding...')
    await asyncio.sleep(5)
    print('Doing Work!')

async def work():
    print('Doing work')
    print('while')
    print('the other guy is sleeping')

async def main():
    await asyncio.gather(sleeper(), work())

asyncio.run(main())
Answered By: Lukas Schmid

Another alternative is by using threading.
I’ve got a simple example here with 2 Threads where the working thread is waiting for the countdown thread to finish and starting. The Main is still working fine.

import threading
import time


def do_something():
    countdown_thread.join()
    print("Starting Task")
    time.sleep(3)
    print("Finished Task")

def countdown(num_of_secs):
    while(num_of_secs):
        time.sleep(1)
        num_of_secs -= 1
        print(num_of_secs)


if __name__ == '__main__':
    countdown_thread = threading.Thread(target=countdown, args=(3,))
    work_thread = threading.Thread(target=do_something)

    countdown_thread.start()
    work_thread.start()

    while True:
        print("Main doing something")
        time.sleep(1)

Example picture for multithreading: Sequential vs Threading

Answered By: LiiVion

The most common and easiest way to implement this would be with a Timer object from the threading library. It would go as follows:

import threading
import time

i = 0
done = False

def show_results():
    print("results from GPIO readings")
    print("=)")
    global done
    done = True   # signal end of while loop

def read_GPIO():
    print("reading GPIO...")


t = threading.Timer(60, show_results)   # task will trigger after 60 seconds
t.start()

# your while loop would go here
read_GPIO()             # do work
while not done:
    print("waiting", i) # doing work while waiting for timer
    time.sleep(1)
    i += 1
    pass

Notice that the time library is used only for illustrative purposes. You could also start the timer recursively to check periodically GPIOs and print results or trigger an event. For more information on the threading library or the Timer object check the docs

Answered By: Wonky
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.