← Назад к вопросам
Во что оборачивается корутина перед помещением в Event Loop
2.4 Senior🔥 131 комментариев
#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
# Корутины и Event Loop: оборачивание в Task
Это критически важный вопрос для понимания того, как asyncio на самом деле работает.
Различие между Coroutine и Task
Корутина — это просто объект, определённый с помощью async def. Она ничего не делает самостоятельно:
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
return "done"
# Создаём корутину
coro = my_coroutine() # Это НЕ выполняется здесь
print(type(coro)) # <class "coroutine">
# Корутина сама по себе ничего не делает
del coro # Просто удалили
Task — это обёртка для корутины в Event Loop:
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
return "done"
async def main():
# Оборачиваем в Task
task = asyncio.create_task(my_coroutine())
# Теперь Event Loop управляет ей
result = await task
return result
asyncio.run(main())
Что происходит при создании Task
Когда корутина помещается в Event Loop, она оборачивается в объект asyncio.Task:
import asyncio
async def example():
return "done"
async def inspect():
# Создаём Task
task = asyncio.create_task(example())
# Task содержит:
# - _coro: сама корутина
# - _state: PENDING, RUNNING, DONE и т.д.
# - _result: результат выполнения
# - _exception: исключение если есть
print(f"Task: {task}")
print(f"Состояние: {task._state}")
print(f"Содержит корутину: {task.get_coro()}")
result = await task
print(f"Результат: {result}")
asyncio.run(inspect())
Последовательное vs Параллельное выполнение
Без оборачивания в Task — последовательно
import asyncio
import time
async def task(name):
await asyncio.sleep(1)
return name
async def sequential():
start = time.time()
# Без Task — ждём каждую
r1 = await task("1") # 1 сек
r2 = await task("2") # +1 сек
r3 = await task("3") # +1 сек
print(f"Время: {time.time() - start:.1f}s") # ~3 сек
asyncio.run(sequential())
С оборачиванием в Task — параллельно
import asyncio
import time
async def task(name):
await asyncio.sleep(1)
return name
async def parallel():
start = time.time()
# С Task — выполняются параллельно
t1 = asyncio.create_task(task("1"))
t2 = asyncio.create_task(task("2"))
t3 = asyncio.create_task(task("3"))
# Event Loop уже запустила все три
r1 = await t1
r2 = await t2
r3 = await t3
print(f"Время: {time.time() - start:.1f}s") # ~1 сек
asyncio.run(parallel())
Task наследует Future
import asyncio
from asyncio import Task, Future
async def example():
return "result"
async def compare():
task = asyncio.create_task(example())
# Task — это подкласс Future
print(f"Task наследует Future: {isinstance(task, Future)}")
print(f"Task наследует Task: {isinstance(task, Task)}")
# Task имеет все методы Future:
# - done(): выполнена ли
# - result(): получить результат
# - set_result(): установить результат
# - cancel(): отменить
await task
print(f"done(): {task.done()}")
print(f"result(): {task.result()}")
asyncio.run(compare())
asyncio.gather() автоматически оборачивает
import asyncio
import time
async def task(n):
await asyncio.sleep(1)
return n
async def main():
start = time.time()
# gather() автоматически оборачивает в Task
results = await asyncio.gather(
task(1), # Task 1
task(2), # Task 2
task(3) # Task 3
)
# Все выполнились параллельно
print(f"Результаты: {results}")
print(f"Время: {time.time() - start:.1f}s") # ~1 сек
asyncio.run(main())
Когда использовать create_task()
Используй asyncio.create_task() когда:
- Нужно параллельное выполнение
- Задачи независимы друг от друга
- Нужно сохранить reference на Task
- Хочешь управлять отменой (task.cancel())
import asyncio
async def main():
# Создаём Task
task = asyncio.create_task(some_coro())
# Можем отменить её
task.cancel()
# Можем проверить состояние
print(f"Отменена: {task.cancelled()}")
Практический пример
import asyncio
async def fetch(url):
print(f"Fetching {url}")
await asyncio.sleep(2)
return f"Data from {url}"
async def main():
# БЕЗ Task — 6 секунд
# r1 = await fetch("url1") # 2 сек
# r2 = await fetch("url2") # 2 сек
# r3 = await fetch("url3") # 2 сек
# С Task — 2 секунды
task1 = asyncio.create_task(fetch("url1"))
task2 = asyncio.create_task(fetch("url2"))
task3 = asyncio.create_task(fetch("url3"))
# Все три работают одновременно
results = await asyncio.gather(task1, task2, task3)
print(results)
asyncio.run(main())
Итог
Корутина — просто объект, ничего не делает сама.
Task — обёртка, которая:
- Позволяет Event Loop управлять выполнением
- Можно запустить параллельно другие Task
- Имеет состояние (pending, done, cancelled)
- Хранит результат или исключение
Золотое правило:
await coro— последовательноasyncio.create_task(coro)илиasyncio.gather()— параллельно
Внутри Event Loop всё работает через Task — это ключ к пониманию asyncio.