In practice, a Timer is probably the simplest way to do what you want.
This code will do the following:
- After 1 second, it prints arg1 arg2
- After 2 seconds, it prints OWLS OWLS OWLS
from threading import Timer def twoArgs(arg1,arg2): print arg1 print arg2 print def nArgs(*args): for each in args: print each #arguments: #how long to wait (in seconds), #what function to call, #what gets passed in r = Timer(1.0, twoArgs, (arg1,arg2)) s = Timer(2.0, nArgs, (OWLS,OWLS,OWLS)) r.start() s.start()
The above code will most likely solve your problem.
For this single-thread version, all you need to do is store the function and its arguments in an object, along with the time at which the function should be run.
Once you have the object containing the function call and the timeout, just periodically check if the function is ready to execute.
The right way to do this is by making a priority queue to store all of the functions we want to run in the future, as shown in the code below.
This code will do the following:
- After 1 second, it prints 20
- After 2 seconds, it prints 132
- After 3 seconds, it quits.
from datetime import datetime, timedelta import heapq # just holds a function, its arguments, and when we want it to execute. class TimeoutFunction: def __init__(self, function, timeout, *args): self.function = function self.args = args self.startTime = datetime.now() + timedelta(0,0,0,timeout) def execute(self): self.function(*self.args) # A todo list for all the TimeoutFunctions we want to execute in the future # They are sorted in the order they should be executed, thanks to heapq class TodoList: def __init__(self): self.todo =  def addToList(self, tFunction): heapq.heappush(self.todo, (tFunction.startTime, tFunction)) def executeReadyFunctions(self): if len(self.todo) > 0: tFunction = heapq.heappop(self.todo) while tFunction and datetime.now() > tFunction.startTime: #execute all the functions that are ready tFunction.execute() if len(self.todo) > 0: tFunction = heapq.heappop(self.todo) else: tFunction = None if tFunction: #this ones not ready yet, push it back on heapq.heappush(self.todo, (tFunction.startTime, tFunction)) def singleArgFunction(x): print str(x) def multiArgFunction(x, y): #Demonstration of passing multiple-argument functions print str(x*y) # Make some TimeoutFunction objects # timeout is in milliseconds a = TimeoutFunction(singleArgFunction, 1000, 20) b = TimeoutFunction(multiArgFunction, 2000, *(11,12)) c = TimeoutFunction(quit, 3000, None) todoList = TodoList() todoList.addToList(a) todoList.addToList(b) todoList.addToList(c) while True: todoList.executeReadyFunctions()
In practice, you would likely have more going on in that while loop than just checking if your timeout functions are ready to go. You might be polling for user input, controlling some hardware, reading data, etc.
You can use signals in python as well (unix only)
import signal, sys # install a SIGALRM handler def handler(signum, frame): print got signal, exiting sys.exit(1) signal.signal(signal.SIGALRM, handler) # emit SIGALRM after 5 secs signal.setitimer(signal.ITIMER_REAL, 5) # do stuff i = 1 while True: if i % 100000 == 0: print i i += 1
There is a nice solution using
asyncio in python 3:
import asyncio def async_call_later(seconds, callback): async def schedule(): await asyncio.sleep(seconds) if asyncio.iscoroutinefunction(callback): await callback() else: callback() asyncio.ensure_future(schedule()) async def do_something_async(): await asyncio.sleep(0.5) print(Now! async) async def main(): print(Scheduling...) async_call_later(3, do_something_async) async_call_later(3, lambda: print(Now!)) print(Waiting...) await asyncio.sleep(4) loop = asyncio.get_event_loop() loop.run_until_complete(main())
Note that the sleep and similar functions in python expect a number of seconds, so I have replicated that. But you can supply fractions if you need milliseconds. (e.g 0.5 => 500ms).
An advantage of this approach over asyncio.call_later is that it only works with a synchronous callback. This implementation
awaits if the callback is a coroutine so it is slightly more robust.