This concise, exampled-base article walks you through some different ways to add a coroutine to an already running event loop in Python.
Using the asyncio.loop.create_task() method
This approach uses the loop.create_task()
method, which creates a new task from the coroutine and schedules it to run on the loop. A task is a subclass of asyncio.Future
that represents a coroutine that is executing or waiting to be executed. Tasks are used to track the progress and state of coroutines, and can also be awaited or cancelled.
Example:
# SlingAcademy.com
# This code uses Python 3.11.4
import asyncio
# define the coroutine
async def my_coroutine():
# do something async
await asyncio.sleep(2)
print("Welcome to Sling Academy!")
# define the main function
async def main():
# get the current event loop
loop = asyncio.get_event_loop()
# check if the event loop is already running
if(loop.is_running()):
print(f"Event loop is already running.")
# create and schedule a new task
task = loop.create_task(my_coroutine())
# wait for the task to complete
await task
# run the main function
asyncio.run(main())
When executing the code, you’ll receive the following messages (with a delay between):
Event loop is already running.
Welcome to Sling Academy!
Using the asyncio.ensure_future() function
The main point here is the asyncio.ensure_future()
function, which is similar to loop.create_task()
but also works with futures and other awaitable objects. A future is an object that represents an eventual result of an asynchronous operation. Futures can be awaited, cancelled, or have callbacks registered to them.
Example (the majority of the code is the same as in the previous example):
# SlingAcademy.com
# This code uses Python 3.11.4
import asyncio
# define the coroutine
async def my_coroutine():
# do something async
await asyncio.sleep(2)
print("Welcome to Sling Academy!")
# define the main function
async def main():
# get the current event loop
loop = asyncio.get_event_loop()
# check if the event loop is already running
if loop.is_running():
print(f"Event loop is already running.")
# create and schedule a new future
future = asyncio.ensure_future(my_coroutine())
# wait for the future to complete
await future
# run the main function
asyncio.run(main())
Using the asyncio.run_coroutine_threadsafe() function
An alternative solution is to utilize the asyncio.run_coroutine_threadsafe()
function, which is helpful when you want to run a coroutine from a different thread than the one running the event loop. This function returns a concurrent.futures.Future
object that can be used to wait for the result or cancel the execution.
Example:
# SlingAcademy.com
# This code uses Python 3.11.4
import asyncio
import threading
# Define a coroutine
async def add(a: int, b: int):
# Mimic a long-running task
print("The program is thinking of the result very hard...")
await asyncio.sleep(1)
# Calculate and return the result
result = a + b
return f"The sum of {a} and {b} is {result}"
# Define a function that runs the coroutine in a thread
def run_in_thread(loop, a: int, b: int):
# Submit the coroutine to the loop
future = asyncio.run_coroutine_threadsafe(add(a, b), loop)
# Wait for the result
print(f"Result: {future.result()}")
if __name__ == "__main__":
# Get the main event loop
loop = asyncio.get_event_loop()
# Create a thread that runs the coroutine
thread = threading.Thread(target=run_in_thread, args=(loop, 4, 5))
# Start the thread
thread.start()
# Run the loop forever
loop.run_forever()
Output:
The program is thinking of the result very hard...
Result: The sum of 4 and 5 is 9
This is an article dedicated to the asyncio.run_coroutine_threadsafe()
function: Python asyncio.run_coroutine_threadsafe() function (with examples).