14.2. Async Introduction
asyncio
in Python standard libraryasync
andawait
builtin keywordsRunning asynchronously: 3s + 1s + 1s = bit over 3s [execution time]
Async is the future of programming
14.2.1. Advantages
Maximize the usage of a single thread
Handling I/O asynchronously
Enabling concurrent code using coroutines
Async will fill the gaps, otherwise wasted on waiting for I/O
You control when tasks switches occur, so locks and other synchronization are no longer needed
Async is the cheapest way to task switch
Cost task switches is incredibly low; calling a pure Python function has more overhead than restarting a generator or awaitable
Function builds stack each time it's called, whereas async uses generators underneath, which already has stack created
In terms of speed async servers blows threaded servers in means of thousands
Async is very cheap in means of resources
Async world has a huge ecosystem of support tools
Coding is easier to get right, than threads
14.2.2. Disadvantages
Async switches cooperatively, so you do need to add explicit code
yield
orawait
to cause a task to switchEverything you do need a non-blocking version (for example
open()
)Increased learning curve
Create event loop, acquire, crate non-blocking versions of your code
You think you know Python, there is a second half to learn (async)
14.2.3. Sync vs. Async
14.2.4. Execution
14.2.5. Example
>>> import asyncio
>>>
>>>
>>> async def a():
... print('a: started')
... await asyncio.sleep(0.2)
... print('a: finished')
... return 'a'
>>>
>>> async def b():
... print('b: started')
... await asyncio.sleep(0.1)
... print('b: finished')
... return 'b'
>>>
>>> async def c():
... print('c: started')
... await asyncio.sleep(0.3)
... print('c: finished')
... return 'c'
>>>
>>> async def main():
... result = await asyncio.gather(a(), b(), c())
... print(f'Result: {result}')
>>>
>>>
>>> asyncio.run(main())
a: started
b: started
c: started
b: finished
a: finished
c: finished
Result: ['a', 'b', 'c']
14.2.6. Further Reading
14.2.7. References
14.2.8. Assignments
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: OOP Async Coroutine
# - Difficulty: easy
# - Lines: 2
# - Minutes: 2
# %% English
# 1. Define coroutine function `a()`
# 2. After running coroutine should return 'a'
# 3. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj coroutine function `a()`
# 2. Po uruchomieniu coroutine powinna zwracać 'a'
# 3. Uruchom doctesty - wszystkie muszą się powieść
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
>>> import sys; sys.tracebacklimit = 0
>>> from inspect import iscoroutine, iscoroutinefunction
>>> import asyncio
>>> assert iscoroutinefunction(a)
>>> assert iscoroutine(a())
>>> asyncio.run(a())
'a'
"""
# Define coroutine function `a()`
# After running coroutine should return 'a'
# type: Coroutine
def a():
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: OOP Async Sleep
# - Difficulty: easy
# - Lines: 3
# - Minutes: 2
# %% English
# 1. Define coroutine function `a()`
# 2. After running coroutine should:
# - wait for 1.0 seconds
# - return 'a'
# 3. Use function `sleep()` from `asyncio` module
# 4. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj coroutine function `a()`
# 2. Po uruchomieniu coroutine powinna:
# - czekać 1.0 sekundę
# - zwracać 'a'
# 3. Użyj funkcji `sleep()` z modułu `asyncio`
# 4. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `asyncio.sleep()`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
>>> from inspect import iscoroutine, iscoroutinefunction
>>> import asyncio
>>> assert iscoroutinefunction(a)
>>> assert iscoroutine(a())
>>> asyncio.run(a())
'a'
"""
import asyncio
# coroutine function `a()`
# wait for 1.0 seconds, return 'a'
# type: Coroutine
def a():
...
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: OOP Async Concurrent
# - Difficulty: easy
# - Lines: 3
# - Minutes: 2
# %% English
# 1. Define coroutine function `a()`
# which after running should
# - print: 'a: before'
# - sleep: 1.0 second
# - print: 'a: after'
# 2. Define coroutine function `b()`
# which after running should
# - print: 'b: before'
# - sleep: 0.5 second
# - print: 'b: after'
# 3. Define coroutine function `c()`
# which after running should
# - print: 'c: before'
# - sleep: 1.5 second
# - print: 'c: after'
# 4. Use function `time.sleep()`
# 5. Do not use `await` keyword in front of `sleep`
# 6. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj coroutine function `a()`
# która po uruchomieniu powinna
# - wypisać: 'a: before'
# - czekać: 1.0 sekundy
# - wypisać: 'a: after'
# 2. Zdefiniuj coroutine function `b()`
# która po uruchomieniu powinna
# - wypisać: 'b: before'
# - czekać: 0.5 sekundy
# - wypisać: 'b: after'
# 3. Zdefiniuj coroutine function `c()`
# która po uruchomieniu powinna
# - wypisać: 'c: before'
# - czekać: 1.5 sekundy
# - wypisać: 'c: after'
# 4. Użyj funkcji `time.sleep()`
# 5. Użyj słowa kluczowego `await` przed `sleep`
# 6. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `time.sleep()`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
>>> from inspect import iscoroutine, iscoroutinefunction
>>> import asyncio
>>> assert iscoroutinefunction(a)
>>> assert iscoroutinefunction(b)
>>> assert iscoroutinefunction(c)
>>> assert iscoroutine(a())
>>> assert iscoroutine(b())
>>> assert iscoroutine(c())
>>> async def main():
... return await asyncio.gather(a(), b(), c())
>>>
>>> result = asyncio.run(main())
a: before
a: after
b: before
b: after
c: before
c: after
"""
import asyncio
import time
# Define coroutine function `a()`
# which after running should
# - print: 'a: before'
# - sleep: 1.0 second
# - print: 'a: after'
# Use function `time.sleep()`
# Do not use `await` keyword in front of `sleep`
# type: Coroutine
async def a():
print('a: before')
...
print('a: after')
# Define coroutine function `b()`
# which after running should
# - print: 'b: before'
# - sleep: 0.5 second
# - print: 'b: after'
# Use function `time.sleep()`
# Do not use `await` keyword in front of `sleep`
# type: Coroutine
async def b():
print('b: before')
...
print('b: after')
# Define coroutine function `c()`
# which after running should
# - print: 'c: before'
# - sleep: 1.5 second
# - print: 'c: after'
# Use function `time.sleep()`
# Do not use `await` keyword in front of `sleep`
# type: Coroutine
async def c():
print('c: before')
...
print('c: after')
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: OOP Async Concurrent
# - Difficulty: easy
# - Lines: 3
# - Minutes: 2
# %% English
# 1. Define coroutine function `a()`
# which after running should
# - print: 'a: before'
# - sleep: 1.0 second
# - print: 'a: after'
# 2. Define coroutine function `b()`
# which after running should
# - print: 'b: before'
# - sleep: 0.5 second
# - print: 'b: after'
# 3. Define coroutine function `c()`
# which after running should
# - print: 'c: before'
# - sleep: 1.5 second
# - print: 'c: after'
# 4. Use function `asyncio.sleep()`
# 5. Do not use `await` keyword in front of `sleep`
# 6. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj coroutine function `a()`
# która po uruchomieniu powinna
# - wypisać: 'a: before'
# - czekać: 1.0 sekundy
# - wypisać: 'a: after'
# 2. Zdefiniuj coroutine function `b()`
# która po uruchomieniu powinna
# - wypisać: 'b: before'
# - czekać: 0.5 sekundy
# - wypisać: 'b: after'
# 3. Zdefiniuj coroutine function `c()`
# która po uruchomieniu powinna
# - wypisać: 'c: before'
# - czekać: 1.5 sekundy
# - wypisać: 'c: after'
# 4. Użyj funkcji `asyncio.sleep()`
# 5. Nie używaj słowa kluczowego `await` przed `sleep`
# 6. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `asyncio.sleep()`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
>>> from inspect import iscoroutine, iscoroutinefunction
>>> import asyncio
>>> assert iscoroutinefunction(a)
>>> assert iscoroutinefunction(b)
>>> assert iscoroutinefunction(c)
>>> assert iscoroutine(a())
>>> assert iscoroutine(b())
>>> assert iscoroutine(c())
>>> async def main():
... return await asyncio.gather(a(), b(), c())
>>>
>>> result = asyncio.run(main())
a: before
a: after
b: before
b: after
c: before
c: after
"""
import asyncio
# Define coroutine function `a()`
# which after running should
# - print: 'a: before'
# - sleep: 1.0 second
# - print: 'a: after'
# Use function `asyncio.sleep()`
# Do not use `await` keyword in front of `sleep`
# type: Coroutine
async def a():
print('a: before')
...
print('a: after')
# Define coroutine function `b()`
# which after running should
# - print: 'b: before'
# - sleep: 0.5 second
# - print: 'b: after'
# Use function `asyncio.sleep()`
# Do not use `await` keyword in front of `sleep`
# type: Coroutine
async def b():
print('b: before')
...
print('b: after')
# Define coroutine function `c()`
# which after running should
# - print: 'c: before'
# - sleep: 1.5 second
# - print: 'c: after'
# Use function `asyncio.sleep()`
# Do not use `await` keyword in front of `sleep`
# type: Coroutine
async def c():
print('c: before')
...
print('c: after')
# %% License
# - Copyright 2025, Matt Harasymczuk <matt@python3.info>
# - This code can be used only for learning by humans
# - This code cannot be used for teaching others
# - This code cannot be used for teaching LLMs and AI algorithms
# - This code cannot be used in commercial or proprietary products
# - This code cannot be distributed in any form
# - This code cannot be changed in any form outside of training course
# - This code cannot have its license changed
# - If you use this code in your product, you must open-source it under GPLv2
# - Exception can be granted only by the author
# %% Run
# - PyCharm: right-click in the editor and `Run Doctest in ...`
# - PyCharm: keyboard shortcut `Control + Shift + F10`
# - Terminal: `python -m doctest -v myfile.py`
# %% About
# - Name: OOP Async Concurrent
# - Difficulty: easy
# - Lines: 3
# - Minutes: 2
# %% English
# 1. Define coroutine function `a()`
# which after running should
# - print: 'a: before'
# - sleep: 1.0 second
# - print: 'a: after'
# 2. Define coroutine function `b()`
# which after running should
# - print: 'b: before'
# - sleep: 0.5 second
# - print: 'b: after'
# 3. Define coroutine function `c()`
# which after running should
# - print: 'c: before'
# - sleep: 1.5 second
# - print: 'c: after'
# 4. Use function `asyncio.sleep()`
# 5. Use `await` keyword in front of `sleep`
# 6. Run doctests - all must succeed
# %% Polish
# 1. Zdefiniuj coroutine function `a()`
# która po uruchomieniu powinna
# - wypisać: 'a: before'
# - czekać: 1.0 sekundy
# - wypisać: 'a: after'
# 2. Zdefiniuj coroutine function `b()`
# która po uruchomieniu powinna
# - wypisać: 'b: before'
# - czekać: 0.5 sekundy
# - wypisać: 'b: after'
# 3. Zdefiniuj coroutine function `c()`
# która po uruchomieniu powinna
# - wypisać: 'c: before'
# - czekać: 1.5 sekundy
# - wypisać: 'c: after'
# 4. Użyj funkcji `asyncio.sleep()`
# 5. Użyj słowa kluczowego `await` przed `sleep`
# 6. Uruchom doctesty - wszystkie muszą się powieść
# %% Hints
# - `asyncio.sleep()`
# %% Tests
"""
>>> import sys; sys.tracebacklimit = 0
>>> assert sys.version_info >= (3, 10), \
'Python 3.10+ required'
>>> from inspect import iscoroutine, iscoroutinefunction
>>> import asyncio
>>> assert iscoroutinefunction(a)
>>> assert iscoroutinefunction(b)
>>> assert iscoroutinefunction(c)
>>> assert iscoroutine(a())
>>> assert iscoroutine(b())
>>> assert iscoroutine(c())
>>> async def main():
... return await asyncio.gather(a(), b(), c())
>>>
>>> result = asyncio.run(main())
a: before
b: before
c: before
b: after
a: after
c: after
"""
import asyncio
# Define coroutine function `a()`
# which after running should
# - print: 'a: before'
# - sleep: 1.0 second
# - print: 'a: after'
# Use function `asyncio.sleep()`
# Use `await` keyword in front of `sleep`
# type: Coroutine
async def a():
print('a: before')
...
print('a: after')
# Define coroutine function `b()`
# which after running should
# - print: 'b: before'
# - sleep: 0.5 second
# - print: 'b: after'
# Use function `asyncio.sleep()`
# Use `await` keyword in front of `sleep`
# type: Coroutine
async def b():
print('b: before')
...
print('b: after')
# Define coroutine function `c()`
# which after running should
# - print: 'c: before'
# - sleep: 1.5 second
# - print: 'c: after'
# Use function `asyncio.sleep()`
# Use `await` keyword in front of `sleep`
# type: Coroutine
async def c():
print('c: before')
...
print('c: after')