Async callbacks in python

How to Use Asyncio Task Done Callback Functions

You can add a done callback function to a task via the add_done_callback() method and specify the function name.

Done callback functions can be removed from a task via the remove_done_callback() method.

In this tutorial, you will discover how to use asyncio task done callback functions in Python.

What is an Asyncio Task

An asyncio Task is an object that schedules and independently runs an asyncio coroutine.

It provides a handle on a scheduled coroutine that an asyncio program can query and use to interact with the coroutine.

An asyncio task is represented via an instance of the asyncio.Task class.

A task is created from a coroutine. It requires a coroutine object, wraps the coroutine, schedules it for execution, and provides ways to interact with it.

A task is executed independently. This means it is scheduled in the asyncio event loop and will execute regardless of what else happens in the coroutine that created it. This is different from executing a coroutine directly, where the caller must wait for it to complete.

Tasks are used to schedule coroutines concurrently. When a coroutine is wrapped into a Task with functions like asyncio.create_task() the coroutine is automatically scheduled to run soon

— Coroutines and Tasks

This function takes a coroutine instance and an optional name for the task and returns an asyncio.Task instance.

Wrap the coro coroutine into a Task and schedule its execution. Return the Task object.

— Coroutines and Tasks

You can learn more about asyncio tasks in the tutorial:

Now that we know about asyncio tasks, let’s look at how we might use done callback functions.

Run your loops using all CPUs, download my FREE book to learn how.

How to Use Callback With a Task

We can add a done callback function to a task via the add_done_callback() method.

This method takes the name of a function to call when the task is done.

The callback function must take the Task instance as an argument.

Recall that a task may be done when the wrapped coroutine finishes normally when it returns, when an unhandled exception is raised or when the task is canceled.

The add_done_callback() method can be used to add or register as many done callback functions as we like.

We can also remove or de-register a callback function via the remove_done_callback() function.

Now that we know how to add and remove done callback functions, let’s look at some worked examples.

Confused by the asyncio module API?
Download my FREE PDF cheat sheet

Example of Adding a Task Done Callback Function

We can explore how to add a done callback function to a task.

In this example, we will define a task coroutine that reports a message and sleeps for a moment.

We will then define a main coroutine that we will use as the entry point to the program. It will report a message, create and schedule the task, then add a done callback function to the task that reports a simple message.

The main coroutine then waits for the task to be completed.

The complete example is listed below.

Running the example starts the asyncio event loop and executes the main() coroutine.

The main() coroutine reports a message, then creates and schedules the task coroutine.

It then adds the done callback function to the task to be executed when the task is finished.

The main() coroutine then suspends and awaits the task to be completed.

The task runs, reports a message, and sleeps for a moment before terminating normally.

After the task completes, the done callback function is called by the event loop, reporting a message.

The main() coroutine resumes, reports its own final message and the program ends.

This example highlights how a done callback can be added to a task and that it is called automatically when the task is done.

Next, let’s look at the case where we may want to add more than one done callback function.

Free Python Asyncio Course

Download my asyncio API cheat sheet and as a bonus you will get FREE access to my 7-day email course on asyncio.

Discover how to use the Python asyncio module including how to define, create, and run new coroutines and how to use non-blocking I/O.

Example of Adding More Than One Task Done Callback Function

A task may have more than one done callback function registered to be called when it completes.

This can be achieved by calling the add_done_callback() function for each function to be registered.

We can explore how to register multiple callback functions to be called when a task finishes.

The example below updates the above example to define two callback functions. The first reports a generic message, and the second reports the details of the task itself.

Both callback functions are added to the task after it is created and scheduled, then called automatically once the task is complete.

The complete example is listed below.

Running the example starts the asyncio event loop and executes the main() coroutine.

The main() coroutine reports a message, then creates and schedules the task coroutine.

It then adds both done callback functions to the task. We expect the callbacks to be executed by the asyncio event loop in the order that they are added.

The main() coroutine then suspends and awaits the task to be completed.

The task runs, reports a message, and sleeps for a moment before terminating normally.

After the task completes, the first done callback function is called by the event loop, reporting a message. Then the second callback function is called, reporting the details of the task itself.

The main() coroutine resumes, reports its own final message and the program ends.

This example highlights how we can add multiple done callback functions to a task.

Next, let’s look at an example of adding, then removing a done callback function.

Overwheled by the python concurrency APIs?
Find relief, download my FREE Python Concurrency Mind Maps

Example of Adding and Removing a Task Done Callback Function

A done callback function can be removed from a task.

This may be required if callbacks need to be executed conditionally and in some cases not executed at all.

The example below adds a callback function to a task after it is created but before it is running.

Then, after the task has been running for a moment, the done callback function is removed to ensure it is not executed when the task finishes.

The complete example is listed below.

Running the example starts the asyncio event loop and executes the main() coroutine.

The main() coroutine reports a message, then creates and schedules the task coroutine.

It then adds the done callback function to the task to be executed when the task is finished.

The main() coroutine then suspends and awaits the task to be completed.

The task runs, reports a message, and sleeps for a moment. This gives the task time to start running.

It then resumes and removes the done callback function from the running task.

The main() coroutine then awaits the task to be completed.

The task completes and the done callback function is not executed, as we intended.

The main() coroutine resumes, reports its own final message and the program ends.

This example highlights how a done callback function can be removed from a running task before it is done.

Next, let’s look at what happens if we attempt to remove a callback that was not added.

Example of Removing a Nonexistent Done Callback Function

It is possible to remove a callback function that was not registered with the task.

This does not cause an error, instead, it has no effect on the task and no indication is provided to the caller that the callback was never registered.

The example below demonstrates this.

Running the example starts the asyncio event loop and executes the main() coroutine.

The main() coroutine reports a message, then creates and schedules the task coroutine.

It then removes a callback from the task that was never added in the first place. This has no effect on the task or on the calling coroutine.

The main() coroutine then suspends and awaits the task to be completed.

The task runs, reports a message, and sleeps for a moment before terminating normally.

After the task completes, no done callback function is executed, as we expect.

The main() coroutine resumes, reports its own final message and the program ends.

This example highlights that we can attempt to remove a done callback that was never registered with no effect.

Next, let’s explore what happens if we add a done callback function after a task is done.

Example of Adding a Done Callback Function After the Task is Done

A done callback function can be added after the task has already been completed.

The effect is that the done callback function will execute as soon as it is able.

The example below demonstrates this. The main coroutine creates and schedules a task, then waits for it to complete. Once the task is done, the main coroutine then adds a done callback function.

The complete example is listed below.

Running the example starts the asyncio event loop and executes the main() coroutine.

The main() coroutine reports a message, then creates and schedules the task coroutine. It then suspends and awaits the task to be completed.

The task runs, reports a message, and sleeps for a moment before terminating normally.

After the task completes, the main() coroutine adds the done callback and then terminates.

Before the asyncio event loop terminates, it executes the done callback function added to the task, reporting its message.

This example highlights that we can add a done callback function to a task after it has been completed.

Next, let’s take a look at what happens if an exception is raised in a done callback function.

Example of Exception in Task Done Callback Function

A done callback function can raise an exception.

Importantly, an exception raised in a done callback function will not impact the asyncio event loop. It also will not impact the task on which it was added nor any other done callback functions that need to be executed.

We can demonstrate this with a worked example.

In this example, two done callback functions are added to a scheduled task. The first callback function fails with an exception. The second operates normally and is unaffected by the failure of the first callback function.

The complete example is listed below.

Running the example starts the asyncio event loop and executes the main() coroutine.

The main() coroutine reports a message, then creates and schedules the task coroutine.

It then adds the two done callback functions to the task to be executed when the task is finished.

The main() coroutine then suspends and awaits the task to be completed.

The task runs, reports a message, and sleeps for a moment before terminating normally.

After the task completes, the first done callback function is called by the event loop, reporting a message and then raising an exception.

The exception is caught by the asyncio event loop and logged using a default logger, in this case to standard output.

The second done callback function is then executed as per normal.

The main() coroutine resumes, reports its own final message and the program ends.

This example highlights how a done callback can fail with an exception, and how the exception will be logged by the event loop and does not impact other done callback functions.

Источник

Читайте также:  What is java platform standard edition
Оцените статью