This tutorial was built on top of Python 3.6.
In this tutorial we are going to be covering Asyncio’s event loop. Some of the material for this tutorial was taken from my book: Learning Concurrency in Python.
The Event Loop
The main component of any asyncio based Python program has to be the underlying event loop. Within this event loop we can (from the official documentation):
- register, execute and cancel calls
- Launch subprocesses and the associated transports for communication with an external program
- Delegate costly function calls to a pool of threads
Essentially all an event loop does is wait for events to happen before matching each event to a function that we have explicitly matched with said type of event.
A good example of this would be a simple web server, say we have an endpoint on our server that serves our website which features a multitude of different pages. Our event loop essentially listens for requests to be made and then matches each of these requests to its associated webpage.
Each of the requests made to our web server in the above example would be
considered a separate
event. These events are then matched to a set function
that we have predefined whenever a said event is triggered.
Let’s take a quick look at how you can define a very simple event loop. In order
to instantiate an event loop we’ll use
asyncio.get_event_loop(), we’ll then
try... finally and within the body of our
try we’ll specify that we
want our newly instantiated event loop to run until it has completed our
import asyncio # Define a coroutine that takes in a future async def myCoroutine(): print("My Coroutine") # Spin up a quick and simple event loop # and run until completed loop = asyncio.get_event_loop() try: loop.run_until_complete(myCoroutine()) finally: loop.close()
We have a number of options for running our event loops, we can either call
run_forever() which will subsequently run our event loop until the
function is called, or we can call
run_until_complete(future) and only run our
event loop until whatever
future object we’ve passed in has completed it’s
The run_until_complete() method
Let’s take a quick look at the
run_until_complete() function. In this example
we’ll define our
myWork() coroutine which we will then pass into our
run_until_complete function and subsequently we should see our event loop run
myWork() coroutine is finished it’s execution.
import asyncio import time async def myWork(): print("Starting Work") time.sleep(5) print("Finishing Work") loop = asyncio.get_event_loop() try: loop.run_until_complete(myWork()) finally: loop.close()
Upon running this you should then see the following output:
$ python3.6 test.py Starting Work Finishing Work
The run_forever() method
The alternative way of starting up your event loop is to call the
run_forever() method which will subsequently start your asyncio based event
loop and have it run indefinitely until the program comes to an end or the
stop() method is called. It should be noted that calling this causes our main
thread to block indefinitely.
Let’s take a look at a quick example which showcases the use of this method.
We’ll first define our
work() coroutine which will feature a while loop that
will run indefinitely and simply print out
Task Executed in 1 second
import asyncio async def work(): while True: await asyncio.sleep(1) print("Task Executed") loop = asyncio.get_event_loop() try: asyncio.ensure_future(work()) loop.run_forever() except KeyboardInterrupt: pass finally: print("Closing Loop") loop.close()
Running Multiple coroutines:
If you wanted to run multiple coroutines indefinitely in parallel then you can
do that by creating your
x number of coroutines and have them run a while loop
each. You would then call
asyncio.ensure_future(function()) in order to
enqueue them onto the loop and they would run indefinitely after that point.
import asyncio import time async def firstWorker(): while True: await asyncio.sleep(1) print("First Worker Executed") async def secondWorker(): while True: await asyncio.sleep(1) print("Second Worker Executed") loop = asyncio.get_event_loop() try: asyncio.ensure_future(firstWorker()) asyncio.ensure_future(secondWorker()) loop.run_forever() except KeyboardInterrupt: pass finally: print("Closing Loop") loop.close()
This should output the following indefinitely:
$ python3.6 run-forever.py First Worker Executed Second Worker Executed First Worker Executed Second Worker Executed First Worker Executed Second Worker Executed
If you found this tutorial useful or you require more assistance then please feel free to leave a comment in the comments section below!