Fixing Python aiohttp RuntimeError: Event Loop Already Running

Updated: January 2, 2024 By: Guest Contributor Post a comment

The ‘RuntimeError: This event loop is already running’ error in Python usually appears when using asynchronous I/O frameworks such as aiohttp along with the asyncio module. The error typically occurs when trying to run an event loop that is already running, which is not allowed in asyncio out-of-the-box. It often surfaces when using Jupyter Notebooks or other environments where an event loop is already present. Below we will discuss several strategies for resolving this issue.

Solution 1: Use nest_asyncio

nest_asyncio is a Python library designed to patch asyncio to allow nested use of asyncio.run and loop.run_until_complete. Just follow the steps below:

  1. Install nest_asyncio by running pip install nest_asyncio.
  2. Import nest_asyncio and patch the event loop at the start of your application, before running any async code:

Example:

import nest_asyncio
nest_asyncio.apply()

Pros:

  • Easy to implement.
  • Does not require significant changes to existing code.

Cons:

  • Introduces an external dependency.
  • Not a standard approach to handling async code.

Solution 2: Use asynchio.run

If you’re able to use Python 3.7 or newer, replacing event loop management with asyncio.run() can effectively handle the ‘event loop is already running’ error.

Replace your event loop code with a single call to asyncio.run():

import asyncio

async def main():
    # Your async code here
    pass

asyncio.run(main())

Pros:

  • Native to the asyncio library, requiring no additional packages.
  • Simplifies code by managing the event loop internally.

Cons:

  • Only available in Python 3.7 and newer.
  • Cannot be used if there is already a running event loop.

Using concurrency libraries

Libraries like Gevent or Tornado provide their own event loop implementations that can be used as alternatives to asyncio’s event loop.

Replace asyncio with a third-party library such as Gevent:

from gevent import monkey
monkey.patch_all()

# replace asyncio functions with Gevent equivalents...

Pros: Can be a complete alternative to asyncio, which may bypass the issue entirely.

Cons:

  • Requires refactoring to switch to another event loop system.
  • May have compatibility issues with libraries expecting native asyncio event loops.

Avoid Using Blocking Functions

Blocking functions inside an async routine can lead to the RuntimeError. Rewrite synchronous functions to be async, and do not use blocking calls like time.sleep() but rather await asyncio.sleep().

Here are the key points:

  1. Identify blocking calls in your asynchronous functions.
  2. Rewrite these functions to be non-blocking.

Here’s how to do it in code:

# Instead of using time.sleep which is blocking
# use the async version from asyncio
await asyncio.sleep(x)

Pros: Promotes better async code practices, improving performance and reliability.

Cons: Requires refactoring and might not be straightforward for complex blocking calls.