← Назад к вопросам
В чем различие между create_task и await в AsyncIO?
1.7 Middle🔥 181 комментариев
#Python Core#Асинхронность и многопоточность
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Различие между create_task и await в AsyncIO
Это фундаментальный вопрос в асинхронном программировании на Python. Разница между ними критична для правильного использования asyncio.
Быстрый ответ
# ❌ НЕПРАВИЛЬНО: блокирует выполнение
await coroutine() # Ждём результата, потом продолжаем
# ✅ ПРАВИЛЬНО: запускает параллельно
task = asyncio.create_task(coroutine()) # Запускаем и сразу продолжаем
1. await — Последовательное выполнение
import asyncio
import time
async def fetch_data(url, delay):
"""Имитирует сетевой запрос"""
print(f"Fetching {url}...")
await asyncio.sleep(delay) # Ждём delay секунд
print(f"Got data from {url}")
return f"Data from {url}"
async def main_with_await():
start = time.time()
# Способ 1: использовать await
result1 = await fetch_data("api1.com", 2) # Ждём 2 секунды
result2 = await fetch_data("api2.com", 2) # Потом ждём ещё 2 секунды
result3 = await fetch_data("api3.com", 2) # И ещё 2 секунды
elapsed = time.time() - start
print(f"\nTotal time: {elapsed:.1f}s")
# Output:
# Fetching api1.com...
# Got data from api1.com
# Fetching api2.com...
# Got data from api2.com
# Fetching api3.com...
# Got data from api3.com
# Total time: 6.0s ⚠️ 6 СЕКУНД! Последовательно
asyncio.run(main_with_await())
Что происходит с await:
- Запускаем fetch_data("api1.com", 2)
- Ждём завершения (2 секунды)
- Продолжаем с fetch_data("api2.com", 2)
- Ждём завершения (2 секунды)
- Продолжаем с fetch_data("api3.com", 2)
- Ждём завершения (2 секунды)
- Итого: 6 секунд (2+2+2)
2. create_task — Параллельное выполнение
async def main_with_create_task():
start = time.time()
# Способ 2: использовать create_task
task1 = asyncio.create_task(fetch_data("api1.com", 2)) # Запускаем
task2 = asyncio.create_task(fetch_data("api2.com", 2)) # Запускаем
task3 = asyncio.create_task(fetch_data("api3.com", 2)) # Запускаем
# Теперь они все выполняются одновременно!
result1 = await task1 # Ждём первого
result2 = await task2 # Ждём второго
result3 = await task3 # Ждём третьего
elapsed = time.time() - start
print(f"\nTotal time: {elapsed:.1f}s")
# Output:
# Fetching api1.com...
# Fetching api2.com...
# Fetching api3.com...
# Got data from api1.com
# Got data from api2.com
# Got data from api3.com
# Total time: 2.0s ✅ 2 СЕКУНДЫ! Параллельно
asyncio.run(main_with_create_task())
Что происходит с create_task:
- Запускаем все три задачи (они стартуют сразу)
- Все три выполняются одновременно
- Ждём первого (максимум 2 секунды, но все три уже работают)
- Итого: 2 секунды (максимум из трёх параллельных)
3. Визуализация разницы
await версия (последовательно):
Task1: |-----|
Task2: |-----|
Task3: |-----|
Time: 0 2 4 6 (секунды)
Утечение времени: 6 секунд
create_task версия (параллельно):
Task1: |-----|
Task2: |-----|
Task3: |-----|
Time: 0 2 4 (секунды)
Утечение времени: 2 секунды
4. Синтаксические различия
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
return "Done"
async def main():
# ============================================
# Способ 1: await — ждём результат сразу
# ============================================
result = await my_coroutine() # Ждём результат
print(result) # Вывелся сразу
# ============================================
# Способ 2: create_task — создаём задачу
# ============================================
task = asyncio.create_task(my_coroutine()) # Создаём task
# Здесь корутина уже выполняется в фоне!
result = await task # Ждём результат
print(result) # Вывелся сразу
# ============================================
# Способ 3: gather для нескольких await
# ============================================
results = await asyncio.gather(
my_coroutine(),
my_coroutine(),
my_coroutine()
) # Все три выполняются параллельно
print(results) # ["Done", "Done", "Done"]
asyncio.run(main())
5. Когда использовать create_task
Использовай create_task когда нужна параллельность
# ✅ ПРАВИЛЬНО: параллельные сетевые запросы
async def fetch_multiple_urls():
tasks = [
asyncio.create_task(fetch_from_api(url))
for url in ["api1.com", "api2.com", "api3.com"]
]
results = await asyncio.gather(*tasks)
return results
# ✅ ПРАВИЛЬНО: фоновые задачи
async def server():
background_task = asyncio.create_task(cleanup_old_files())
# Сервер работает, cleanup выполняется в фоне
await serve_requests()
# После завершения основной работы
await background_task
# ✅ ПРАВИЛЬНО: долгоживущие задачи
async def main():
# Запустить мониторинг и основное приложение параллельно
monitor_task = asyncio.create_task(monitor_health())
app_task = asyncio.create_task(run_app())
await asyncio.gather(monitor_task, app_task)
6. Когда использовать await
Используй await когда нужна строгая последовательность
# ✅ ПРАВИЛЬНО: последовательные зависящие операции
async def create_user():
user_data = await fetch_user_schema() # Зависит от следующей
user = await save_user(user_data) # Зависит от предыдущей
await send_email(user) # Зависит от предыдущей
return user
# ✅ ПРАВИЛЬНО: одна операция с результатом
async def get_single_value():
result = await fetch_from_db() # Нужен результат
return result * 2 # Используем результат
# ✅ ПРАВИЛЬНО: когда задачи зависимы
async def pipeline():
# Каждый шаг зависит от результата предыдущего
step1 = await process_step1() # Выводит 100
step2 = await process_step2(step1) # Использует 100
step3 = await process_step3(step2) # Использует результат
7. Сравнение подходов
async def demo():
"""Сравнение различных подходов"""
# ❌ МЕДЛЕННО: последовательный await (6 секунд)
await task1()
await task2()
await task3()
# ✅ БЫСТРО: параллельный create_task (2 секунды)
t1 = asyncio.create_task(task1())
t2 = asyncio.create_task(task2())
t3 = asyncio.create_task(task3())
await asyncio.gather(t1, t2, t3)
# ✅ БЫСТРО: gather напрямую (2 секунды, но меньше кода)
await asyncio.gather(task1(), task2(), task3())
# ✅ БЫСТРО: TaskGroup (Python 3.11+)
async with asyncio.TaskGroup() as tg:
tg.create_task(task1())
tg.create_task(task2())
tg.create_task(task3())
8. Обработка исключений
# ❌ ПЛОХО: await скрывает исключение
async def bad_error_handling():
try:
await failing_coroutine() # Если бросит исключение
except Exception as e:
print(f"Caught: {e}")
# ✅ ПРАВИЛЬНО: create_task сохраняет исключение в task
async def good_error_handling():
task = asyncio.create_task(failing_coroutine())
try:
result = await task # Исключение выведется здесь
except Exception as e:
print(f"Caught: {e}")
# ✅ ПРАВИЛЬНО: gather обработает исключения
async def gather_error_handling():
try:
results = await asyncio.gather(
task1(),
task2(),
return_exceptions=True # Вернуть исключения вместо их выброса
)
except Exception as e:
print(f"One of tasks failed: {e}")
9. Реальный пример: обработка множества запросов
import asyncio
import aiohttp
from typing import List
async def fetch_user(session, user_id: int) -> dict:
"""Получить данные пользователя"""
async with session.get(f"https://api.example.com/users/{user_id}") as resp:
return await resp.json()
async def fetch_all_users_slow(user_ids: List[int]) -> List[dict]:
"""❌ МЕДЛЕННЫЙ СПОСОБ: последовательно"""
results = []
async with aiohttp.ClientSession() as session:
for user_id in user_ids:
user = await fetch_user(session, user_id) # Ждём каждого
results.append(user)
# Время: N * latency (если latency=100ms и 100 юзеров = 10 секунд)
return results
async def fetch_all_users_fast(user_ids: List[int]) -> List[dict]:
"""✅ БЫСТРЫЙ СПОСОБ: параллельно"""
async with aiohttp.ClientSession() as session:
tasks = [
asyncio.create_task(fetch_user(session, user_id))
for user_id in user_ids
]
results = await asyncio.gather(*tasks)
# Время: max(latency) (если latency=100ms = всего 100ms для 100 юзеров)
return results
# Или более современный способ (Python 3.11+)
async def fetch_all_users_modern(user_ids: List[int]) -> List[dict]:
"""✅ СОВРЕМЕННЫЙ СПОСОБ: TaskGroup"""
async with aiohttp.ClientSession() as session:
async with asyncio.TaskGroup() as tg:
tasks = [
tg.create_task(fetch_user(session, user_id))
for user_id in user_ids
]
return [task.result() for task in tasks]
10. Таблица сравнения
| Аспект | await | create_task |
|---|---|---|
| Способ запуска | Синхронный | Асинхронный |
| Когда стартует | Сейчас | Сразу в фоне |
| Результат | Возвращается | Нужно await |
| Параллельность | ❌ Нет (последовательно) | ✅ Да (параллельно) |
| Время выполнения | sum(времена задач) | max(времена задач) |
| Когда использовать | Зависимые задачи | Независимые задачи |
| Синтаксис | result = await func() | task = asyncio.create_task(func()) |
| Исключения | Выбрасываются сразу | Сохраняются в task |
11. Рекомендации
# ✅ BEST PRACTICES:
# 1. Используй create_task для параллельных операций
for url in urls:
asyncio.create_task(fetch(url)) # Все запустятся параллельно
# 2. Используй await для зависимых операций
user_data = await fetch_user() # Нужны данные перед следующим
user_profile = await fetch_profile(user_data) # Зависит от предыдущего
# 3. Используй gather для нескольких параллельных task'ов
results = await asyncio.gather(
fetch(url1),
fetch(url2),
fetch(url3)
)
# 4. В Python 3.11+ используй TaskGroup
async with asyncio.TaskGroup() as tg:
for url in urls:
tg.create_task(fetch(url))
# 5. Никогда не забывай await на результат task'а
task = asyncio.create_task(my_coroutine())
result = await task # Обязательно await!
Итоговый вывод
await — это синхронное ожидание результата корутины. Используется когда результат нужен сразу для следующей операции.
create_task — это запуск корутины в фоне. Используется когда нужна параллельность и можно продолжить работу, пока задача выполняется.
Ключевой момент:
await= ЖДЁШЬ (последовательно)create_task= ЗАПУСКАЕШЬ В ФОНЕ (параллельно)
Для производительности сетевых приложений — всегда используй create_task или gather для параллельных операций. Это может ускорить приложение в 10+ раз!