How to Get and Set Asyncio Task Names

November 12, 2022 Python Asyncio

Asyncio tasks are assigned default names when they are created.

Nevertheless, it can be beneficial to give tasks meaningful names. This can help when introspecting the asyncio event loop, when logging, and when debugging.

Task names can be made more meaningful by including task-specific data, such as ids.

In this tutorial, you will discover how to set and get the name of an asyncio task.

After completing this tutorial, you will know:

Let's get started.

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.

A Task is an object that manages an independently running coroutine.

-- PEP 3156 – Asynchronous IO Support Rebooted: the "asyncio" Module

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

We can create a task using the asyncio.create_task() function.

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

For example:

...
# create and schedule a task
task = asyncio.create_task(coro)

You can learn more about asyncio tasks in the tutorial:

Now that we know about asyncio tasks, let's look at how we might set and get task names.

How to Set The Task Name

A task may have a name.

This name can be helpful if multiple tasks are created from the same coroutine and we need some way to tell them apart programmatically.

Using a task name can be used when logging, debugging, and conditionally performing operations on asyncio tasks.

The name of a task can be set when the task is created from a coroutine via the "name" argument to the asyncio.create_task() function.

For example:

...
# create a task from a coroutine
task = asyncio.create_task(task_coroutine(), name='MyTask')

The name for the task can also be set via the set_name() method.

For example:

...
# set the name of the task
task.set_name('MyTask')

We can retrieve the name of a task via the get_name() method.

For example:

...
# get the name of a task
name = task.get_name()

Now that we are familiar with how to set and get the task name, let's look at some examples.

Example of Getting the Default Task Name

Tasks are assigned a default name.

They have names with the format 'Task-%d', where '%d' refers to the sequential task number created in the event loop.

For example, the first few tasks will have the default names Task-1, Task-2, Task-3, and so on.

We can explore the default name assigned to an asyncio task.

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

We will then define the main coroutine that will be used as the entry point to the asyncio program. The main coroutine will report a message, then create and schedule the task coroutine. It will then wait for the task to be completed.

Once completed, the main coroutine will print the task and its name.

The complete example is listed below.

# SuperFastPython.com
# example of getting the default task name
import asyncio

# define a coroutine for a task
async def task_coroutine():
    # report a message
    print('executing the task')
    # block for a moment
    await asyncio.sleep(1)

# custom coroutine
async def main():
    # report a message
    print('main coroutine started')
    # create and schedule the task
    task = asyncio.create_task(task_coroutine())
    # wait for the task to complete
    await task
    # report the task
    print(task)
    # report the task name
    print(f'name: {task.get_name()}')
    # report a final message
    print('main coroutine done')

# start the asyncio program
asyncio.run(main())

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

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

The main() coroutine resumes.

It prints a string representation of the task, which we can see shows the name of the task as 'Task-2'.

It then reports just the name of the task, which we can see matches the name included in the string representation of the task.

This example highlights that tasks are assigned a name by default that follows a predictable naming convention.

main coroutine started
executing the task
<Task finished name='Task-2' coro=<task_coroutine() done, defined at ...> result=None>
name: Task-2
main coroutine done

Next, let's look at how we might set the name of a task when it is created.

Example of Setting the Task Name When Creating

We can set the name of a task when it is created and scheduled via an argument to the create_task() function.

We can explore how to set a custom name for a task.

The example below updates the previous example to set a custom name for the task.

# SuperFastPython.com
# example of setting the task name when it is created
import asyncio

# define a coroutine for a task
async def task_coroutine():
    # report a message
    print('executing the task')
    # block for a moment
    await asyncio.sleep(1)

# custom coroutine
async def main():
    # report a message
    print('main coroutine started')
    # create and schedule the task
    task = asyncio.create_task(task_coroutine(), name="MyTask")
    # wait for the task to complete
    await task
    # report the task
    print(task)
    # report the task name
    print(f'name: {task.get_name()}')
    # report a final message
    print('main coroutine done')

# start the asyncio program
asyncio.run(main())

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 with a custom name.

It then suspends and awaits the task to be completed.

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

The main() coroutine resumes.

It prints a string representation of the task, which we can see shows the custom name of 'MyTask'.

It then reports just the name of the task, which we can see matches the name included in the string representation of the task.

This example highlights that we can assign a task a distinct name when it is created.

main coroutine started
executing the task
<Task finished name='MyTask' coro=<task_coroutine() done, defined at ...> result=None>
name: MyTask
main coroutine done

Example of Setting the Task Name While Running

We can set the name of the task after it has been created, such as when it is scheduled or running.

The example below updates the above example to first create and schedule the task, report the default name, then change the name while the task is running.

The complete example is listed below.

# SuperFastPython.com
# example of setting the task name while it is running
import asyncio

# define a coroutine for a task
async def task_coroutine():
    # report a message
    print('executing the task')
    # block for a moment
    await asyncio.sleep(1)

# custom coroutine
async def main():
    # report a message
    print('main coroutine started')
    # create and schedule the task
    task = asyncio.create_task(task_coroutine())
    # report the task
    print(task)
    # wait a moment
    await asyncio.sleep(0.1)
    # set the name
    task.set_name('MyTask')
    # wait for the task to finish
    await task
    # report the task
    print(task)
    # report the task name
    print(f'name: {task.get_name()}')
    # report a final message
    print('main coroutine done')

# start the asyncio program
asyncio.run(main())

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 prints a string representation of the task, showing the default task name.

The main() coroutine then waits a moment.

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

The main() coroutine resumes and changes the name of the task. It then waits for the task to be completed.

The task resumes and then terminates normally.

The main() coroutine resumes. It reports a string representation of the task and the task name directly, both showing the custom name.

This highlights that we can change the name of a task while it is running.

main coroutine started
<Task pending name='Task-2' coro=<task_coroutine() running at ...>>
executing the task
<Task finished name='MyTask' coro=<task_coroutine() done, defined at ...> result=None>
name: MyTask
main coroutine done

Next, let's look at how we might get the name of the task from within the task itself.

Example of Getting the Task Name Within the Task

We can get the currently running task in the event loop via the asyncio.current_task() function.

This function can be called within a coroutine to get a reference to the Task object that wraps it.

We can explore getting a Task instance within a coroutine and then using the task instance to allow the coroutine (task) to access its own name.

This can be helpful with tasks such as logging and operating conditionally based on the task name.

The example below updates the above example so that the task coroutine acquires the Task instance for itself and then reports the details of the task, including its name.

# SuperFastPython.com
# example of getting the task name within the task
import asyncio

# define a coroutine for a task
async def task_coroutine():
    # report a message
    print('executing the task')
    # get the current task
    task = asyncio.current_task()
    # report the current task
    print(task)
    # report the name of the current task
    print(task.get_name())
    # block for a moment
    await asyncio.sleep(1)

# custom coroutine
async def main():
    # report a message
    print('main coroutine started')
    # create and schedule the task
    task = asyncio.create_task(task_coroutine())
    # wait for the task to complete
    await task
    # report a final message
    print('main coroutine done')

# start the asyncio program
asyncio.run(main())

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 and reports a message. It then acquires the Task object that is currently running, which is the task that is executing the coroutine. It then reports the details of the task and its name, before sleeping and terminating normally.

The main() coroutine resumes and closes the program.

This example highlights that tasks are able to execute their own names.

main coroutine started
executing the task
<Task pending name='Task-2' coro=<task_coroutine() running at ...> cb=[Task.task_wakeup()]>
Task-2
main coroutine done

Takeaways

You now know how to set and get the name of an asyncio task in Python.