Asyncio basic II

Tutorial on how to use Asyncio in a Jupyter Notebook

This story will show the basic of using Asyncio in a Jupyter Notebook

Prerequisites

Using Python 3.12. Need to install a few packages via pip along the way, but that will be obvious once we get to that.

The Problem with Notebooks and Asyncio

It is important to understand that when running jobs in asyncio, we are still running in the same thread. Asyncio tasks are functions that run concurrently but under the control of the same event loop. Jupyter already runs in an event loop, so that causes problems, and we have to write code slightly differently for code that runs in jupyter and code that doesn't.

Examples: Running Asyncio in Jupyter Notebooks

To effectively use asyncio in Jupyter Notebooks without relying on external libraries, you can use the built-in asyncio module. Below are examples to help you get started.

Example 1: Basic Asyncio Function

import asyncio

# Define an asynchronous function
async def say_hello():
    await asyncio.sleep(1)
    print("Hello, Asyncio!")

# Run the function using asyncio.run
asyncio.run(say_hello())

This example demonstrates a simple asynchronous function that prints a message after a delay. However, this approach will not work directly in Jupyter Notebooks due to the existing event loop.

Example 2: Using Asyncio in Jupyter Notebooks

To resolve the event loop conflict in Jupyter, you can use the asyncio module's event loop directly. Here's how:

import asyncio

# Define an asynchronous function
async def say_hello():
    await asyncio.sleep(1)
    print("Hello, Asyncio in Jupyter!")

# Get the current event loop or create a new one
loop = asyncio.get_event_loop()

# Run the function using the event loop
if loop.is_running():
    # If the loop is already running (e.g., in Jupyter), use create_task
    task = loop.create_task(say_hello())
else:
    # Otherwise, run the function normally
    loop.run_until_complete(say_hello())

This approach avoids external dependencies and works seamlessly in Jupyter Notebooks.

Example 3: Running Multiple Asyncio Tasks

You can also run multiple tasks concurrently using asyncio.gather:

import asyncio

# Define multiple asynchronous functions
async def task1():
    await asyncio.sleep(1)
    print("Task 1 completed")

async def task2():
    await asyncio.sleep(2)
    print("Task 2 completed")

# Get the current event loop or create a new one
loop = asyncio.get_event_loop()

# Run the tasks concurrently
if loop.is_running():
    # If the loop is already running (e.g., in Jupyter), use create_task
    tasks = [loop.create_task(task1()), loop.create_task(task2())]
else:
    # Otherwise, run the tasks normally
    loop.run_until_complete(asyncio.gather(task1(), task2()))

This example demonstrates how to run multiple tasks concurrently, showcasing the power of asyncio in handling asynchronous operations without relying on external libraries.

Conclusion

By using the built-in asyncio module, you can overcome the event loop conflict in Jupyter Notebooks and fully leverage the capabilities of asyncio. These examples should help you get started with writing and running asynchronous code in your notebooks.

References

Python Concurrency With Asyncio

Ryan V on youtube

Jupyterlab, Python3, asyncio – asynchronous tasks in a notebook background thread

nocomplexity.com

Colab notebook