Ответ
Библиотека asyncio
в Python предоставляет инфраструктуру для написания конкурентного кода с использованием корутин (coroutines) через синтаксис async/await
. Она позволяет эффективно управлять множеством I/O-bound операций без использования потоков или процессов.
Почему используется: asyncio
идеально подходит для задач, где много времени тратится на ожидание (например, сетевые запросы, чтение/запись файлов, запросы к базам данных), позволяя программе переключаться между задачами вместо блокировки.
Основные компоненты:
- Event Loop (Цикл событий): Сердце
asyncio
, которое управляет выполнением задач, переключаясь между ними при обнаружении блокирующих операций (I/O,asyncio.sleep
). - Coroutines (Корутины): Специальные функции, объявленные с
async def
, которые могут приостанавливать своё выполнение с помощьюawait
и передавать управление обратно в Event Loop. - Tasks (Задачи): Обёртки вокруг корутин, которые планируются для выполнения в Event Loop.
asyncio.create_task()
превращает корутину в задачу. - Futures (Будущие объекты): Объекты, представляющие результат асинхронной операции, который будет доступен в будущем.
Пример:
import asyncio
import time
async def fetch_data(delay, data_id):
print(f"[{time.time():.2f}] Начинаем загрузку данных {data_id}...")
await asyncio.sleep(delay) # Имитация асинхронной I/O операции
print(f"[{time.time():.2f}] Данные {data_id} загружены")
return {"id": data_id, "status": "loaded", "delay": delay}
async def main():
print(f"[{time.time():.2f}] Запуск main...")
# Создаем несколько задач, которые будут выполняться конкурентно
task1 = asyncio.create_task(fetch_data(2, 1))
task2 = asyncio.create_task(fetch_data(1, 2))
print(f"[{time.time():.2f}] Делаем что-то параллельно, пока задачи выполняются...")
# Ожидаем завершения всех задач
results = await asyncio.gather(task1, task2)
print(f"[{time.time():.2f}] Все задачи завершены. Результаты: {results}")
if __name__ == "__main__":
asyncio.run(main())
Ключевые моменты:
- Ключевое слово
await
используется для приостановки выполнения текущей корутины и передачи управления Event Loop, который может запустить другую задачу. asyncio.run()
запускает Event Loop и выполняет главную корутину.- Задачи (
Tasks
) выполняются конкурентно (псевдопараллельно), но не параллельно в истинном смысле (если нет многопоточности или многопроцессорности). asyncio
наиболее эффективен для I/O-bound задач (сеть, файлы, базы данных), где ожидание внешних ресурсов является основным узким местом, но не для CPU-bound задач (интенсивные вычисления), которые блокируют Event Loop.