Перейти к содержанию

Начало урока

Асинхронный Python: asyncio

Один поток, тысячи перекрывающихся операций ввода-вывода, без колбэков

Главная идея: asyncio выполняет множество операций, ограниченных вводом-выводом, конкурентно в одном потоке. Корутина работает, пока не встретит await на чём-то ещё не готовом (сокет, таймер, ответ); в этот момент она приостанавливается и возвращает управление циклу событий, который запускает другую готовую корутину. На процессоре ничего не выполняется параллельно — вместо этого перекрывается время ожидания. Это кооперативная конкурентность: задачи добровольно уступают управление на каждом await.
К концу вы сможете:
  • объяснить разницу между конкурентностью и параллелизмом и почему asyncio нацелен на задачи ввода-вывода;
  • писать корутины async def и запускать их через asyncio.run;
  • организовывать настоящую конкурентность через asyncio.create_task и asyncio.gather;
  • ограничивать работу по времени через asyncio.timeout и правильно обрабатывать CancelledError;
  • потреблять потоки данных через async for и писать async-генераторы;
  • распознавать ловушки: забытый await, блокирующие вызовы, замораживающие цикл, и злоупотребление на CPU-задачах.

1. Конкурентность — это не параллелизм

Параллелизм означает, что несколько вещей выполняются в один и тот же момент на разных ядрах процессора (то, что даёт multiprocessing). Конкурентность означает, что несколько задач в процессе выполнения и чередуются, но в любой отдельный момент реально работает только одна. asyncio даёт конкурентность, а не параллелизм: он использует один поток и перекрывает ожидание.

Это идеально подходит для задач, ограниченных вводом-выводом — HTTP-запросы, запросы к базе данных, чтение файлов, работа с сокетами — где программа проводит большую часть времени в ожидании чего-то внешнего. Пока один запрос ждёт прихода байтов, цикл запускает другой. Для задач, ограниченных процессором (перемалывание чисел, разбор огромных данных), asyncio не даёт ускорения вообще, потому что нет простоя, который можно перекрыть; там используйте процессы или потоки.

Аналогия: один повар с множеством кастрюль. Хороший повар не стоит, наблюдая, как кипит одна кастрюля. Он ставит пасту и, пока она варится, режет овощи; когда звенит таймер духовки, занимается ею. Один повар (один поток), много блюд в работе (много корутин). Повар никогда не готовит два блюда в один и тот же момент, но общее время ужина сокращается, потому что ожидание перекрывается. asyncio — это тот повар; каждый await — это момент "это требует времени, займусь пока чем-то другим".

Продолжите этот урок на YourAIZone

В полном уроке — объяснение целиком, разобранные примеры, частые ошибки, тесты с мгновенной проверкой и ИИ-репетитор. Начните сразу как гость или создайте аккаунт, чтобы сохранять прогресс.

В полном уроке

  • Объяснение целиком
  • Разобранные примеры
  • Частые ошибки и как их избежать
  • Тестовые вопросы: 15
  • ИИ-репетитор, который отвечает на вопросы по теме
  • Отслеживание прогресса для ученика, родителей и учителя