Generally, an Event is a planned occasion or function that happens at a specified time in future.
In a computer science context, it can be a task (function/callable) that we want to execute at some time in future. We might also want to execute multiple tasks after a specified time interval.
Python has a module named sched which lets us schedule events in the future by executing callable at some time in the future. It provides us with an API that lets us execute callable at a specified time in the future as well as after a specified delay from the current time. It has also provisions to use different time-related functions with different time units with the scheduler.
As a part of this tutorial, we have explained how to use Python module sched to schedule events to be executed in future. We can schedule tasks that we want to run at a specified time in future or after a specified time interval. Apart from scheduling events, we have explained how to cancel events, create a scheduler with different time units, schedule events with different priorities, retrieve pending events, etc.
Below, we have listed important sections of tutorial to give an overview of material covered.
The process of scheduling events through sched module requires us to follow a list of simple steps.
Please make a note that events will start executing only after the call to run() method of scheduler instance. If there is a delay in calling run() method after the creation of events then events might get delayed as well if their time of execution has already passed when we started scheduler using run().
We'll now explain the usage of various methods of sched module with simple examples that will make them easy to understand and grasp.
Our first example simply creates one event that executes after 3 seconds of its creation.
We have created a simple function named addition(a,b) which takes two integer/floats as input and returns their addition as output. We have then created a scheduler using scheduler() method of sched module with its default parameter.
Then we have created an event using enter() method of the scheduler instance which kicks off after 3 seconds of its creation. At last, we have called run() method on the scheduler to start it.
The events get executed only after the scheduler has started.
Below we have listed down important attributes of this method.
The scheduler() method returns an instance of type scheduler. The scheduler class is thread-safe hence can be used with a multi-threading setup.
Below is a list of parameter explanations.
We can give parameter values to the function as input by using either of argument or kwargs parameter.
The enter() method returns the object of type Event which has information about time when the event is scheduled to execute as well information about priority, reference to action function, and its arguments.
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
print("Time : ", time.monotonic())
print("Result : ", a+b)
s = sched.scheduler()
print("Start Time : ", datetime.now(), "\n")
event1 = s.enter(3, 1, addition, argument = (10,20))
print("Event Created : ", event1)
s.run()
print("\nEnd Time : ", datetime.now())
Please make a note that if any event takes a long time to execute which if pass the time of execution of future events then future events will be delayed by the extra time taken by the event. There are methods to cancel events that will be introduced in future examples.
We have used two python modules in above example named time and datetime which are used to measure time and create date-time objects. Please feel free to check below link if you want to learn about them in detail.
Our second example has exactly the same code as our first example with only a difference in a call to enter() method. We have passed parameter values as dictionary for addition function using kwargs parameter.
Please make a note that sched module does not provide a way to collect return values if a function is returning some value (it'll be lost). It just executes the code inside of the function. If you want to maintain the return value of the function then you'll need to use some workaround like global variables or shared data structures available through the threading module in case of a multi-threading example.
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
print("Time : ", time.monotonic())
print("Result : ", a+b)
s = sched.scheduler()
print("Start Time : ", datetime.now(), "\n")
event1 = s.enter(3, 1, addition, kwargs = {"a":10, "b":20})
print("Event Created : ", event1)
s.run()
print("\nEnd Time : ", datetime.now())
Our third example demonstrates how we can schedule events in the future at a particular time by using enterabs() method.
Our majority of code is the same as our previous example with few minor changes. We are recording the time before the creation of the event and adding 5 units to it to create a new timestamp. We are then giving this time to enterabs() method to run the event after five-time units have passed.
Below is an explanation of the parameters.
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
print("Time : ", time.monotonic())
print("Result : ", a+b)
s = sched.scheduler()
print("Start Time : ", datetime.now(), "\n")
current_time = time.monotonic()
five_seconds_past_curr_time = current_time + 5
event1 = s.enterabs(five_seconds_past_curr_time, 1, addition, kwargs = {"a":10, "b":20})
print("Current Time : ", current_time)
print("\nEvent Created : ", event1)
s.run()
print("\nEnd Time : ", datetime.now())
As a part of our fourth example, we have demonstrated how we can use functions with different time units with the scheduler.
We have created a function named minute_delay_func() which takes as input number and delays execution by that many minutes. It uses sleep() method of time module for this. We have used time() function of time module as timefunc. It returns time as a number of seconds passed since Jan 1, 1971, and is based on a second-time unit. We have called enter() function with a delay of 0.5 which should start the event after 0.5 time units after its creation. The 0.5 time units in our case will become 30 seconds delay based on minute_delay_func.
The majority of our remaining code is almost the same as our previous example.
import sched
from datetime import datetime
import time
def minute_delay_func(delay=1):
time.sleep(delay * 60)
def hour_delay_func(delay=1):
time.sleep(delay * 60 * 60)
def addition(a,b):
print("\nInside Addition : ", datetime.now())
print("Time : ", time.time())
print("Result : ", a+b)
s = sched.scheduler(timefunc=time.time, delayfunc=minute_delay_func)
print("Start Time : ", datetime.now(), "\n")
event1 = s.enter(0.5, 1, addition, kwargs = {"a":10, "b":20})
print("Event Created : ", event1)
s.run()
print("\nEnd Time : ", datetime.now())
As a part of our fifth example, we demonstrate how we can schedule more than one event and how different priority values affect the execution of events that are scheduled to run at the same time. We are using time.time() function as our time unit function of scheduler.
We have created five events. The first two start after 5 seconds delay of their creation and has a priority of 5 and 10 respectively. The next two start after 3 seconds delay of their creation and has a priority of 20 and 15 respectively. The last event starts after 1 second of its creation and has a priority of 25. All events execute our addition() function with different arguments to catch difference in execution sequence.
We can notice from the output that the fifth event runs first. Events 3 and 4 had the same execution time (3 seconds after creation) but different priorities. Event 3 had a priority of 20 and event 4 had a priority of 15, hence the scheduler executes event 4 first because lower priority means a higher chance of execution. Event 1 and 2 also had the same execution time (5 seconds after creation) but different priorities. Event 1 had a priority of 5 and event 2 had a priority of 10, hence the scheduler executes event 1 first due to its high priority.
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
print("Time : ", time.time())
print("Result : ", a+b)
s = sched.scheduler(timefunc=time.time)
print("Start Time : ", datetime.now())
current_time = time.time()
event1 = s.enterabs(current_time +5, 5, addition, kwargs = {"a":10, "b":20})
event2 = s.enterabs(current_time +5, 10, addition, kwargs = {"a":20, "b":30})
event3 = s.enterabs(current_time +3, 20, addition, kwargs = {"a":30, "b":40})
event4 = s.enterabs(current_time +3, 15, addition, kwargs = {"a":40, "b":50})
event5 = s.enterabs(current_time +1, 25, addition, kwargs = {"a":50, "b":60})
s.run()
print("\nEnd Time : ", datetime.now())
Our sixth example demonstrates to us how we can get details of pending events at any time. Our code for this part is almost the same as our previous example with the minor addition of code to the previous example.
We have introduced the usage of queue attribute and empty() method of scheduler instance as a part of this example.
The queue attribute returns a list of events that are still pending for execution. It'll have events in the order in which they are pending for execution. It's a read-only attribute.
The empty() method returns boolean value True indicating that queue is empty hence not pending events to execute else False.
We have introduced code in addition method which checks whether the queue is empty and if it’s not empty then prints the number of events that are still pending. We are also printing a number of events that are pending at the beginning.
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
if not s.empty():
print("Pending Events : ", len(s.queue))
print("Result : ", a+b)
s = sched.scheduler(timefunc=time.time)
print("Start Time : ", datetime.now())
current_time = time.time()
event1 = s.enterabs(current_time +5, 5, addition, kwargs = {"a":10, "b":20})
event2 = s.enterabs(current_time +5, 10, addition, kwargs = {"a":20, "b":30})
event3 = s.enterabs(current_time +3, 20, addition, kwargs = {"a":30, "b":40})
event4 = s.enterabs(current_time +3, 15, addition, kwargs = {"a":40, "b":50})
event5 = s.enterabs(current_time +1, 25, addition, kwargs = {"a":50, "b":60})
print("\nPending Events at Beginning : ", len(s.queue))
s.run()
print("\nEnd Time : ", datetime.now())
As a part of our seventh example, we are demonstrating how we can cancel any pending event. Our code for this part is almost the same as our previous example with few additions and few modifications.
We can cancel events using cancel(event) method of the scheduler instance. We have modified our code for the addition where we have added a loop which goes through all events. It then checks if the time pending for execution of the event is more than 15 seconds then cancel that event.
We have modified our code where we create events to have all events a same priority. All the remaining code is almost the same as our previous examples.
When we run the code the only event which had more than 15 seconds pending to run was our fifth event which gets canceled. It would have printed the result of 110 of addition if got chance to execute.
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
if not s.empty():
print("Pending Events : ", len(s.queue))
events = s.queue
for event in events:
diff = event.time - time.time()
if diff > 15:
print("Cancelling Event : {}".format(event))
s.cancel(event)
print("Result : ", a+b)
s = sched.scheduler(timefunc=time.time)
print("Start Time : ", datetime.now(), "\n")
current_time = time.time()
event1 = s.enterabs(current_time +5, 1, addition, kwargs = {"a":10, "b":20})
event2 = s.enterabs(current_time +10, 1, addition, kwargs = {"a":20, "b":30})
event3 = s.enterabs(current_time +15, 1, addition, kwargs = {"a":30, "b":40})
event4 = s.enterabs(current_time +20, 1, addition, kwargs = {"a":40, "b":50})
event5 = s.enterabs(current_time +25, 1, addition, kwargs = {"a":50, "b":60})
s.run()
print("\nEnd Time : ", datetime.now())
Our eighth example again demonstrates how we can cancel events. The code for this example is almost the same as our previous example but with a minor change in condition in addition() method which checks for canceling events. We have changed the condition which cancels events that are scheduled to run after more than 5 seconds from the current time and have a priority greater than 5 seconds. We are canceling events that are a little far away to execute in the future and have low priority. We have also modified the priority of five events during creation.
When we run the below code, 2 events get canceled (events 2 and 5).
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
if not s.empty():
print("Pending Events : ", len(s.queue))
events = s.queue
for event in events:
diff = event.time - time.time()
if diff > 5 and event.priority > 5:
print("Cancelling Event : {}".format(event))
s.cancel(event)
print("Result : ", a+b)
s = sched.scheduler(timefunc=time.time)
print("Start Time : ", datetime.now(), "\n")
current_time = time.time()
event1 = s.enterabs(current_time +5, 10, addition, kwargs = {"a":10, "b":20})
event2 = s.enterabs(current_time +15, 7, addition, kwargs = {"a":20, "b":30})
event3 = s.enterabs(current_time +15, 4, addition, kwargs = {"a":30, "b":40})
event4 = s.enterabs(current_time +20, 3, addition, kwargs = {"a":40, "b":50})
event5 = s.enterabs(current_time +20, 10, addition, kwargs = {"a":50, "b":60})
s.run()
print("\nEnd Time : ", datetime.now())
Our ninth example demonstrates us if somehow the call to run() method of scheduler gets delayed and the time to execute event has passed then it'll execute events immediately after it starts for which time has passed.
Our code for this example with exactly the same as our first example with the addition of 1 line before the call to run(). We have introduced a sleep time of 5 seconds before starting the scheduler. The event is created and scheduled to run 3 seconds after its creation. This will result in the event getting executed immediately once the scheduler has started because its time to run has already passed.
import sched
from datetime import datetime
import time
def addition(a,b):
print("\nInside Addition : ", datetime.now())
print("Result : ", a+b)
s = sched.scheduler()
print("Start Time : ", datetime.now(), "\n")
event1 = s.enter(3, 1, addition, argument = (10,20))
print("Event Created : ", event1)
time.sleep(5)
s.run()
print("\nEnd Time : ", datetime.now())
If you are more comfortable learning through video tutorials then we would recommend that you subscribe to our YouTube channel.
When going through coding examples, it's quite common to have doubts and errors.
If you have doubts about some code examples or are stuck somewhere when trying our code, send us an email at coderzcolumn07@gmail.com. We'll help you or point you in the direction where you can find a solution to your problem.
You can even send us a mail if you are trying something new and need guidance regarding coding. We'll try to respond as soon as possible.
If you want to