Асинхронность и потоки в Python: asyncio, TaskGroup и free-threading
Зачем нужна конкурентность, async/await, TaskGroup, потоки и GIL. Для опытных: TaskGroup.cancel (3.15), free-threaded сборка (3.13–3.14), субинтерпретаторы (3.14).
- Запускать сетевые задачи конкурентно
- Управлять группой задач
- Понимать, когда нужна сборка без GIL
Início da aula
Три курса валют — три секунды ожидания
- Каждый запрос к API курсов ≈ 1 с ожидания сети
- Подряд: 3.0 с, вместе: 1.0 с
- Процессор всё это время простаивает
Трекер научился переводить траты в рубли, и для этого спрашивает курсы валют у внешнего сервиса: доллар, евро, юань. Каждый ответ идёт около секунды, и программа покорно ждёт их по очереди — три секунды. При этом процессор почти всё время ничего не делает: он просто ждёт ответа по сети. Если отправить три запроса одновременно и ждать их вместе, выйдет одна секунда. Как это сделать — и почему потоки здесь не единственный ответ, — разберём сегодня.
$ uv run rates_seq.py
подряд 3.0 с
$ uv run rates_async.py
вместе 1.0 с
Ждать и считать — разные задачи
- I/O-bound: сеть, диск, база — ждём ответа
- CPU-bound: расчёты — процессор занят
- Для ожидания — asyncio или потоки, для расчётов — процессы
Сначала главное различие, без которого дальше ничего не понять. Представьте повара. Если он поставил воду и ждёт кипения, он может за это время нарезать овощи, а потом поставить духовку — один повар, много дел, потому что основное время занимает ожидание. Это задачи ввода-вывода: сеть, диск, база данных. А если он вручную месит тесто, параллельно ничего не сделаешь — руки заняты. Это вычислительные задачи. Для них нужны дополнительные повара.
async и await: функция, которая умеет ждать
- async def — корутина: вызов не выполняет, а создаёт объект
- await — «подожди, а пока займись другим»
- asyncio.run(main()) — запустить цикл событий
Асинхронный код в Python строится на двух словах. Async перед def объявляет корутину — функцию, которая умеет приостанавливаться. Await внутри неё говорит: здесь я буду ждать, а ты, цикл событий, пока займись другими задачами. Тот самый повар: поставил воду, сказал await и пошёл резать овощи. Запускается всё это функцией run. Важная деталь: внутри асинхронного кода нельзя пользоваться обычным sleep или блокирующими запросами — они остановят весь цикл.
import asyncio
async def fetch_rate(currency: str) -> float:
await asyncio.sleep(1) # имитация запроса к API
return 90.0
async def main() -> None:
for cur in ["USD", "EUR", "CNY"]:
rate = await fetch_rate(cur) # ждём по очереди
print(cur, rate)
asyncio.run(main()) # ~3 секунды
A aula completa é para assinantes
Mais 10 slides na versão completa.
O vídeo, todos os slides, anotações, testes, tutor de IA e entrevista ficam disponíveis após entrar e assinar.
Entrar ou cadastrar-se AssinarConteúdo da aula
- Три курса валют — три секунды ожидания
- Ждать и считать — разные задачи
- async и await: функция, которая умеет ждать
- TaskGroup: запустить вместе и дождаться всех
- Ошибка в одной задаче отменяет остальные
- Грабли: забыли await
- GIL: почему потоки не ускоряют расчёты
- ❓ Стоп-проверка: что выбрать?
- 💡 Разбор: ждём — asyncio или потоки, считаем — процессы
- Что нового: TaskGroup.cancel (3.15)
- Что нового: Python без GIL (3.13–3.14, PEP 703 и 779)
- Что нового: субинтерпретаторы (3.14, PEP 734)
- Итог: курсы валют за секунду, расчёты — на всех ядрах
Artigos sobre esta aula
- Asyncio em Python: async/await, TaskGroup, threads, multiprocessing e GIL
- Como baixar e instalar o Python no Windows, macOS e Linux: passo a passo
- Strings em Python: métodos split, replace, strip, join, fatias e f-strings
- Módulos e pacotes em Python: import, pip, venv e bibliotecas em linguagem simples
- Como aprender Python do zero: plano de estudos para iniciantes passo a passo
Todas as aulas do curso
- Python 3.15 с нуля и для опытных: что нового и как учить
- Python 3.15: установка, REPL и первый скрипт за десять минут
- Переменные, числа и строки в Python: f-строки и t-строки
- Условия, циклы и match/case в Python: управляем ходом программы
- Списки, кортежи, словари и множества: frozendict в Python 3.15
- Comprehensions в Python: распаковка * и ** внутри (PEP 798)
- Функции и аннотации типов в Python: от def до sentinel
- Ошибки и исключения в Python 3.15: читаем трейсбек и подсказки «Did you mean»
- Модули, пакеты и ленивые импорты в Python 3.15 (PEP 810)
- Файлы, JSON и CSV в Python: pathlib и UTF-8 по умолчанию
- Классы и dataclasses в Python: ООП без лишнего кода
- Асинхронность и потоки в Python: asyncio, TaskGroup и free-threading
- Профилирование Python 3.15: Tachyon вместо cProfile и итоговый проект