Zalgorithm

Running coroutines in Python

Declare coroutines with the async/await syntax:

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)

Simply calling a coroutine function will not schedule it to be executed. It just returns a coroutine object:

In [1]: import asyncio

In [2]: async def say_after(delay, what):
   ...:     await asyncio.sleep(delay)
   ...:     print(what)
   ...:

In [3]: say_after(2, "hello")
Out[3]: <coroutine object say_after at 0x7f935037cd40>

asyncio.run #

The asyncio.run() function is the top-level entry point for calling asynchronous functions in an application.

Running an asyncio Program :

asyncio.run(coro, *, debug=None, loop_factory=None)¶ Execute coro in an asyncio event loop and return the result.

The argument can be any awaitable object.

This function runs the awaitable, taking care of managing the asyncio event loop, finalizing asynchronous generators, and closing the executor.

import asyncio


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)


async def main():
    await say_after(1, "hello world")


if __name__ == "__main__":
    asyncio.run(main())

Awaiting coroutines versus awaiting tasks #

Awaiting coroutines #

Awaiting two coroutines, the code will print “hello” after waiting 1 second, then print “world” after waiting another 2 seconds:

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)


async def await_coroutine_example():
    print("starting await_coroutine_example()")
    print(f"started at: {time.strftime('%X')}")
    await say_after(1, "hello")
    await say_after(2, "world")
    print(f"finished at: {time.strftime('%X')}")


async def main():
    await await_coroutine_example()
    # await await_task_example()
    # await task_group_example()


if __name__ == "__main__":
    asyncio.run(main())


# starting await_coroutine_example()
# started at: 14:07:32
# hello
# world
# finished at: 14:07:35

Awaiting tasks #

The asyncio.create_task() function creates tasks that will be run concurrently when awaited on:

import asyncio
import time


async def say_after(delay, what):
    await asyncio.sleep(delay)
    print(what)


async def await_task_example():
    print("starting await_task_example()")
    print(f"started at: {time.strftime('%X')}")
    task1 = asyncio.create_task(say_after(1, "hello"))
    task2 = asyncio.create_task(say_after(2, "world"))
    await task1
    await task2
    print(f"finished at: {time.strftime('%X')}")


async def main():
    await await_task_example()


if __name__ == "__main__":
    asyncio.run(main())

# starting await_task_example()
# started at: 14:09:37
# hello
# world
# finished at: 14:09:39

Note that this finished 1 second earlier than when the coroutines were awaited on: task1 and task2 were run concurrently.

Using TaskGroup as an alternative to create_task #

The previous example can be rewritten using asyncio.TaskGroup :

# equivalent to await_task_example()
async def task_group_example():
    print("starting task_group_example()")
    print(f"started at: {time.strftime('%X')}")
    async with asyncio.TaskGroup() as tg:
        task1 = tg.create_task(say_after(1, "hello"))
        task2 = tg.create_task(say_after(2, "world"))

    # the task1 and task2 assignment wasn't needed here. The call to await task
    # is implicit when the context manager exits
    print(f"finished at: {time.strftime('%X')}")


async def main():
    await task_group_example()


if __name__ == "__main__":
    asyncio.run(main())


# starting task_group_example()
# started at: 14:16:33
# hello
# world
# finished at: 14:16:35

async with asyncio.TaskGroup() creates an asynchronous context manager that holds a group of tasks. Tasks can be added to the group using create_task(). All tasks are awaited when the context manager exits.

References #

docs.python.org. “Coroutines and Tasks.” Accessed on: February 4, 2026. https://docs.python.org/3/library/asyncio-task.html .

docs.python.org. “Asyncio runner.” Accessed on: February 4, 2026. https://docs.python.org/3/library/asyncio-runner.html .