Антон Ларичев
Модуль asyncio в Python — основы асинхронного программирования
Введение
Модуль asyncio — это стандартная библиотека Python для написания асинхронного кода. Он предоставляет событийный цикл (event loop), корутины, задачи и примитивы синхронизации, которые позволяют эффективно обрабатывать операции ввода-вывода без блокировки основного потока выполнения.
В этой статье мы разберём ключевые компоненты asyncio, научимся создавать и запускать корутины, управлять задачами и использовать событийный цикл для построения асинхронных приложений.
Что такое событийный цикл
Событийный цикл (event loop) — это центральный механизм asyncio. Он управляет выполнением корутин, обрабатывает операции ввода-вывода и планирует обратные вызовы. Можно представить его как диспетчер, который решает, какая задача должна выполняться в данный момент.
import asyncio
async def main():
print("Привет из событийного цикла!")
# Запуск событийного цикла
asyncio.run(main())
Функция asyncio.run() — это точка входа в асинхронный код. Она создаёт новый событийный цикл, запускает переданную корутину и закрывает цикл после её завершения.
Корутины и их создание
Корутина — это специальная функция, объявленная с ключевым словом async def. В отличие от обычной функции, корутина не выполняется сразу при вызове — она возвращает объект корутины, который нужно запустить через событийный цикл.
import asyncio
async def privetstvie(imya):
# Имитируем асинхронную задержку
await asyncio.sleep(1)
return f"Привет, {imya}!"
async def main():
# Вызов корутины с ожиданием результата
rezultat = await privetstvie("Мир")
print(rezultat)
asyncio.run(main())
Ключевое слово await приостанавливает выполнение текущей корутины до тех пор, пока ожидаемая операция не завершится. В это время событийный цикл может выполнять другие задачи.
Задачи (Tasks)
Задачи позволяют запускать несколько корутин параллельно. Когда вы оборачиваете корутину в задачу, она начинает выполняться в фоне, не блокируя остальной код.
import asyncio
async def zagruzka(url, zaderjka):
# Имитируем загрузку данных
print(f"Начинаю загрузку {url}...")
await asyncio.sleep(zaderjka)
print(f"Загрузка {url} завершена!")
return f"Данные с {url}"
async def main():
# Создаём задачи для параллельного выполнения
zadacha1 = asyncio.create_task(zagruzka("api/users", 2))
zadacha2 = asyncio.create_task(zagruzka("api/posts", 1))
zadacha3 = asyncio.create_task(zagruzka("api/comments", 3))
# Ожидаем завершения всех задач
rezultat1 = await zadacha1
rezultat2 = await zadacha2
rezultat3 = await zadacha3
print(f"Получено: {rezultat1}, {rezultat2}, {rezultat3}")
asyncio.run(main())
В этом примере три загрузки выполняются параллельно, и общее время выполнения составит около 3 секунд (по самой долгой задаче), а не 6 секунд при последовательном выполнении.
Если вы хотите детальнее изучить асинхронное программирование в Python — приходите на наш большой курс Продвинутый Python. На курсе 171 урок и 22 упражнения, AI-тренажёры для практики 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.
Функция asyncio.gather
Функция asyncio.gather() — удобный способ запустить несколько корутин одновременно и собрать все результаты в один список.
import asyncio
async def poluchit_dannye(istochnik, zaderjka):
await asyncio.sleep(zaderjka)
return f"Данные из {istochnik}"
async def main():
# Запускаем три корутины параллельно
rezultaty = await asyncio.gather(
poluchit_dannye("база данных", 2),
poluchit_dannye("внешний API", 3),
poluchit_dannye("кэш", 1),
)
for rezultat in rezultaty:
print(rezultat)
asyncio.run(main())
Результаты возвращаются в том же порядке, в котором были переданы корутины, независимо от того, какая из них завершилась первой.
Таймауты с asyncio.wait_for
Иногда нужно ограничить время ожидания операции. Для этого используется asyncio.wait_for():
import asyncio
async def dolgaya_operaciya():
# Операция, которая выполняется 10 секунд
await asyncio.sleep(10)
return "Готово"
async def main():
try:
# Устанавливаем таймаут в 3 секунды
rezultat = await asyncio.wait_for(dolgaya_operaciya(), timeout=3.0)
print(rezultat)
except asyncio.TimeoutError:
print("Операция превысила лимит времени!")
asyncio.run(main())
Асинхронные генераторы и итераторы
Python поддерживает асинхронные версии генераторов и итераторов с помощью async for:
import asyncio
async def asinhronniy_generator(n):
for i in range(n):
# Имитируем асинхронное получение данных
await asyncio.sleep(0.5)
yield i * 2
async def main():
async for znachenie in asinhronniy_generator(5):
print(f"Получено значение: {znachenie}")
asyncio.run(main())
Частые ошибки
- Забыть await перед вызовом корутины — без
awaitкорутина не выполнится, а вернёт объект корутины. Python выдаст предупреждениеRuntimeWarning: coroutine was never awaited. - Вызов asyncio.run() внутри уже запущенного событийного цикла — это приведёт к ошибке
RuntimeError. Вместо этого используйтеawaitилиasyncio.create_task(). - Использование блокирующих операций в асинхронном коде — функции вроде
time.sleep()или синхронные сетевые вызовы заблокируют весь событийный цикл. Используйтеasyncio.sleep()и асинхронные библиотеки. - Не обрабатывать исключения в задачах — если задача выбросит исключение и оно не будет обработано, оно может быть потеряно до момента сборки мусора.
Частозадаваемые вопросы
Чем asyncio отличается от потоков (threading)?
Asyncio использует кооперативную многозадачность в одном потоке — корутины сами уступают управление через await. Потоки используют вытесняющую многозадачность, где переключение между потоками происходит на уровне ОС. Asyncio лучше подходит для задач с большим количеством операций ввода-вывода, а потоки — для CPU-интенсивных задач.
Можно ли использовать asyncio с обычными синхронными функциями?
Да, для этого используйте asyncio.to_thread() (Python 3.9+) или loop.run_in_executor(), чтобы запустить синхронную функцию в отдельном потоке без блокировки событийного цикла.
Когда стоит использовать asyncio.gather, а когда asyncio.create_task?
asyncio.gather() удобен, когда вам нужно дождаться завершения группы корутин и получить все результаты. create_task() больше подходит для задач, которые запускаются в фоне и с которыми вы работаете по отдельности.
Заключение
Модуль asyncio — мощный инструмент для написания эффективного асинхронного кода в Python. Событийный цикл, корутины и задачи позволяют обрабатывать тысячи операций ввода-вывода без создания множества потоков. Для закрепления навыков асинхронного программирования рекомендуем курс Продвинутый Python.
В первых 3 модулях курса доступно бесплатное содержание, что позволяет разобраться в основах и понять структуру курса до покупки полного доступа.
Постройте личный план изучения Python до уровня Middle — бесплатно!
Python — часть карты развития Backend
100+ шагов развития
30 бесплатных лекций
300 бонусных рублей на счет
Все гайды по Python
Лучшие курсы по теме

Основы Python
Антон Ларичев
Nest.js с нуля
Антон Ларичев