Ответ
Цикл событий в asyncio узнает о завершении корутины через объекты Task и Future.
Ключевые компоненты механизма:
-
Future: Это объект-заместитель, который представляет конечный результат асинхронной операции. Он может находиться в состоянии ожидания (pending) или завершения (finished) и хранить либо результат, либо исключение. -
Task: Это подклассFuture, специально предназначенный для выполнения корутин в цикле событий. Когда вы создаете задачу с помощьюasyncio.create_task(my_coro()), вы, по сути, говорите циклу событий: "Вот корутина, начни ее выполнять и дай мнеTask, чтобы я мог отслеживать ее состояние".
Как это работает:
- Когда корутина завершается (через
returnилиraise Exception), обернувший ееTaskперехватывает результат или исключение. Taskустанавливает этот результат в свой внутреннийFutureи меняет свое состояние на "завершено".Taskуведомляет цикл событий о своем завершении, вызывая специальные коллбэки. Если какая-то другая корутина ожидала эту задачу черезawait, ее выполнение возобновляется.
Пример:
import asyncio
async def fetch_data():
print("Начинаю загрузку данных...")
await asyncio.sleep(2) # Имитация долгой операции
print("Данные загружены")
return {"data": 123}
async def main():
print("Создаю задачу для fetch_data")
# 1. Корутина оборачивается в Task и планируется к выполнению
task = asyncio.create_task(fetch_data())
# 2. main() приостанавливается и ждет, пока task не завершится
# К task привязывается коллбэк, который возобновит main()
result = await task
# 3. После завершения task, main() возобновляется, и результат доступен
print(f"Задача завершена: {task.done()}")
print(f"Полученный результат: {result}")
asyncio.run(main())
Таким образом, цикл событий не "опрашивает" задачи, а реагирует на события их завершения через систему коллбэков, привязанных к объектам Future/Task.