A conceptual overview of asyncio
NOTE: this is not a tutorial. Check out the links in the References section.
EDIT: (Feb 4, 2026) I’ve learned something, but am going to try a more hands-on approach. See notes/ The Trio Python async concurrency library.
EDIT2: (Feb4, 2026) for where I’m at, the Trio tutorial feels like a better introduction to asynchronous programming.
More useful notes:
- notes / Running coroutines in Python
- notes / The Trio Python async concurrency library
- notes / Textual TUI events (the last part of the ‘async message handlers’ section)
- notes / asyncio subprocesses
“Modern versions of Python have support for ‘asynchronous code’ using something called ‘coroutines’,
with async and await syntax.”1
coroutines #
A coroutine object is what is returned by an async def function.
The terms “asynchronous function” (or “coroutine function”) and “coroutine object” are often conflated as coroutine. I find that a tad confusing. In this article, coroutine will exclusively mean “coroutine object” – the thing produced by executing a coroutine function.2
A coroutine can be paused and resumed at various points within the function’s body. The pausing and resuming are what allow for asynchronous behavior3
Regular functions versus asynchronous functions #
Calling an asynchronous function (“a coroutine function”) returns a coroutine object:
In [4]: def foo_regular():
...: print("Calling the function invokes its code")
...:
In [5]: foo_regular()
Calling the function invokes its code
In [7]: async def foo_asynchronous():
...: print("Calling this function returns a coroutine")
...:
In [8]: foo_asynchronous()
Out[8]: <coroutine object foo_asynchronous at 0x7f32d9f43d00>
The coroutine object has to be explicitly started. Creating the coroutine (e.g. calling
foo_asynchronous()) does not start it.
Python coroutines and generators #
Coroutines and coroutine functions were built into the Python language on top of the scaffolding of generators.2
Like a coroutine, calling a generator function doesn’t run the function:
In [9]: def foo_bar_baz():
...: yield "foo"
...: yield "bar"
...: yield "baz"
...:
In [10]: foo_bar_baz()
Out[10]: <generator object foo_bar_baz at 0x7f32db0401a0>
In [11]: fbb = foo_bar_baz()
In [13]: next(fbb)
Out[13]: 'foo'
In [14]: next(fbb)
Out[14]: 'bar'
In [15]: next(fbb)
Out[15]: 'baz'
In [16]: next(fbb)
Tasks #
Tasks are coroutines (not coroutine functions) that are tied to an event-loop.
The recommended way to create tasks is with
asyncio.create_task()
.
Creating a task adds a callback to run the task to the event loop’s collection of jobs.
Managing the event loop #
import asyncio
async def add_ab(a, b):
print(f"a+b={a + b}")
async def main():
asyncio.create_task(add_ab(2, 3))
asyncio.create_task(add_ab(3, 4))
if __name__ == "__main__":
asyncio.run(main())
# ❯ uv run main.py
# a+b=5
# a+b=7
Await #
await is a Python keyword that’s used either as:
await <coroutine>
await <task>
The behaviour of await depends on whether a coroutine or a task is being awaited. (This needs
clarification.)
See: notes/ Running coroutines in Python
References #
docs.python.org (Python 3.14.3). “A Conceptual Overview of asyncio.” Last updated: Feb 03, 2026. https://docs.python.org/3/howto/a-conceptual-overview-of-asyncio.html .
docs.python.org (Python 3.14.3). “asyncio — Asynchronous I/O.” Last updated: Feb 03, 2026. https://docs.python.org/3/library/asyncio.html .
docs.python.org (Python 3.14.3). “Subprocesses.” Last updated: Feb 03, 2026. https://docs.python.org/3/library/asyncio-subprocess.html .
FastAPI documentation. “Concurrency and async / await.” Accessed on: Feb 03, 2026. https://fastapi.tiangolo.com/async/ .
anordin95. “a-conceptual-overview-of-asyncio.” Accessed on: Feb 03, 2026, https://github.com/anordin95/a-conceptual-overview-of-asyncio .
-
FastAPI documentation, “Concurrency and async / await,” Accessed on: Feb 03, 2026, https://fastapi.tiangolo.com/async/ . ↩︎
-
anordin95, “a-conceptual-overview-of-asyncio,” Accessed on: Feb 03, 2026, https://github.com/anordin95/a-conceptual-overview-of-asyncio . ↩︎ ↩︎
-
anordin95, “a-conceptual-overview-of-asyncio,” Accessed on: Feb 03, 2026, https://github.com/anordin95/a-conceptual-overview-of-asyncio . ↩︎