Python asyncio: What are coroutines and event loops?

Updated: July 31, 2023 By: Khue Post a comment

This concise, straight-to-the-point article is about coroutines and event loops, the two foundation concepts in Python asynchronous programming.

What is a coroutine?

A coroutine is a special kind of function that can pause and resume its execution at certain points, allowing other coroutines to run in the meantime. Coroutines are declared with the async keyword, and can be awaited from other coroutines.

Example:

# SlingAcademy.com
# This code uses Python 3.11.4
import asyncio

# Define the say_hello() coroutine that prints a message (Hello) and then pauses for 1 second before printing another message (Sling Academy!)
async def say_hello():
    print("Hello")
    # Pause for 1 second
    await asyncio.sleep(1)  
    print("Sling Academy!")

# The say_hello() coroutine is called from the main() coroutine
async def main():
    await say_hello()  

# Run the main() coroutine
asyncio.run(main())

Output:

Hello
Sling Academy!

In the code snippet above, we used the asyncio.run() function, which creates a new event loop, runs a coroutine until it completes, and then closes the loop. Let’s dig deeper into event loops in the next section.

What is an event loop?

An event loop is an object that manages the execution of coroutines, as well as other asynchronous tasks such as network IO operations, subprocesses, timers, etc. The event loop runs one coroutine at a time and switches to another one when the current one is blocked by an await expression or a blocking operation.

There are 3 common ways to create an event loop in Python:

1. Using the asyncio.run() function (like in the example in the previous section).

2. Using the asyncio.get_event_loop() function, which returns the current event loop for the current OS thread. If there is no current event loop, it will create a new one. You can then use the loop.run_until_complete() method to run a coroutine until it completes. For example:

# SlingAcademy.com
# This code uses Python 3.11.4
import asyncio

async def hello():
    print("Hello buddy!")
    await asyncio.sleep(1)
    print("Welcome to Sling Academy!")

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(hello())
loop.close()

Output (with a delay between the first and the second messages):

Hello buddy!
Welcome to Sling Academy!

3. Use the asyncio.new_event_loop() function, which creates and returns a new event loop object. You can then set it as the current event loop for the current OS thread using the asyncio.set_event_loop() function. You can then use the loop.run_until_complete() method to run a coroutine until it completes. For example:

# SlingAcademy.com
# This code uses Python 3.11.4
import asyncio

async def count():
    print("One")
    await asyncio.sleep(1)
    print("Two")
    await asyncio.sleep(1)
    print("Three")

loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
loop.run_until_complete(count())
loop.close()

Output (with a delay between two prints):

One
Two
Three

Afterword

The above sections are just basic knowledge for those who are new to the world of concurrency and asynchronous programming in Python. You can find more advanced stuff throughout this series: Python Asynchronous Programming Tutorials. Feel free to leave a comment if you find something outdated or any issues related to code examples in this article. Goodbye!