Sling Academy
Home/Python/Python: Add a coroutine to an already running event loop

Python: Add a coroutine to an already running event loop

Last updated: August 10, 2023

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).

Next Article: Understanding thread-safe in Python: Explained with examples

Previous Article: Python asyncio.loop.create_server() method (with examples)

Series: Python Asynchronous Programming Tutorials

Python

You May Also Like

  • Python Warning: Secure coding is not enabled for restorable state
  • Python TypeError: write() argument must be str, not bytes
  • 4 ways to install Python modules on Windows without admin rights
  • Python TypeError: object of type ‘NoneType’ has no len()
  • Python: How to access command-line arguments (3 approaches)
  • Understanding ‘Never’ type in Python 3.11+ (5 examples)
  • Python: 3 Ways to Retrieve City/Country from IP Address
  • Using Type Aliases in Python: A Practical Guide (with Examples)
  • Python: Defining distinct types using NewType class
  • Using Optional Type in Python (explained with examples)
  • Python: How to Override Methods in Classes
  • Python: Define Generic Types for Lists of Nested Dictionaries
  • Python: Defining type for a list that can contain both numbers and strings
  • Using TypeGuard in Python (Python 3.10+)
  • Python: Using ‘NoReturn’ type with functions
  • Type Casting in Python: The Ultimate Guide (with Examples)
  • Python: Using type hints with class methods and properties
  • Python: Typing a function with default parameters
  • Python: Typing a function that can return multiple types