Asynchronous programming is a powerful technique that can be used to improve the performance and scalability of Python applications.

Lets see how we can use asyncio to wait until a long running task is finished without blocking main thread. This is useful if you are running a very time consuming task wait until a post request completes and we get the status code, or a database query, and so on. Basically we dont want to make our application unresponsive while a task is running.

In the example below, I am using easy to understand example of summing two numbers. In reality, we have lot of post/get/update/delete/put requests, and database writes etc. and using these will complicate the example below.

import asyncio

async def long_running_task(task_status, num1, num2):
    """
    Sum two numbers
    """

    result = num1 + num2

    # Set the status flag to indicate that the task is completed.
    task_status.set()

    return result

async def start(num1, num2):
  """
  Returns the sum of two numbers.
  """

  task_status = asyncio.Event()

  # Start the long-running task in a separate coroutine.
  task = asyncio.create_task(long_running_task(task_status, num1, num2))

  # Poll the status of the task in the main thread.
  while not task_status.is_set():
    # Do some other work in the main thread.
    # ...

    # Check the status of the task periodically.
    await asyncio.sleep(0.1)

    # Return the result of long running task.
    return await task

# Sum two numbers using asyncio.
result = await my_function(10, 29)

print(result)

Lets go through the code and see how it works:

The long_running_task() function is a coroutine. This means that it can be executed concurrently with other tasks.

This function is adding two numbers and then sets the task_status event object to indicate that it is finished executing

async def long_running_task(task_status, num1, num2):
    """
    Sum two numbers
    """

    result = num1 + num2

    # Set the status flag to indicate that the task is completed.
    task_status.set()

    return result

We are using await below to wait until coroutine finishes and returns the result.

The is_set() method is a method of the Event class in the asyncio library. It is used to check if the event has been set.

An event object is a way to signal that something has happened. It can be used to synchronize multiple tasks in an asynchronous program.

To set an event, you can call the set() method on the event object. To check if an event has been set, you can call the is_set() method on the event object.

async def start(num1, num2):
    """
    Returns the sum of two numbers.
    """

    # Create an event object to track the status of the long_running_task() function.
    task_status = asyncio.Event()

    # Start the long_running_task() function in a separate coroutine. The create_task() function creates a new coroutine and returns a Task object. The Task object can be used to track the status of the coroutine and to wait for it to finish executing.
    task = asyncio.create_task(long_running_task(task_status, num1, num2))

    # Poll the status of the task in the main thread. The is_set() method on the event object will return True if the event has been set, and False otherwise.
    while not task_status.is_set():
      # Do some other work in the main thread.
      # ...

      # Check the status of the task periodically. The sleep() function suspends the current coroutine for the specified number of seconds.
      await asyncio.sleep(0.1)

    # Return the result of long running task. The await keyword is used to wait for the coroutine to finish executing.
    return await task

Published

Category

Asynchronous Programming

Tags

Contact