← Назад к вопросам
Что будет если не использовать await в асинхронной функции?
1.8 Middle🔥 291 комментариев
#DevOps и инфраструктура
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Что будет если не использовать await в асинхронной функции?
Это критичный баг, который приводит к проблемам с race conditions и потере данных. Давайте разберёмся.
Основное правило
Если функция асинхронная — её результат нужно await-ить!
async def fetch_user(user_id: int):
# Имитируем задержку БД (1 сек)
await asyncio.sleep(1)
return {"id": user_id, "name": "John"}
async def main():
# НЕПРАВИЛЬНО: забыли await
result = fetch_user(1) # Возвращает Coroutine объект
print(result) # <coroutine object fetch_user at 0x7f8b8c8c5f40>
print(type(result)) # <class coroutine>
# ПРАВИЛЬНО: используем await
result = await fetch_user(1)
print(result) # {"id": 1, "name": "John"}
Что происходит без await
При отсутствии await функция не выполняется. Вместо этого возвращается Coroutine объект — это как повисшая задача.
import asyncio
from datetime import datetime
async def slow_operation():
print(f"[{datetime.now()}] Операция началась")
await asyncio.sleep(2) # Долгая операция
print(f"[{datetime.now()}] Операция завершена")
return "Результат"
async def main():
print(f"[{datetime.now()}] main() начался")
# БЕЗ await
coro = slow_operation() # Корутина создана, но не выполняется!
print(f"[{datetime.now()}] После вызова slow_operation()")
# Консоль:
# [12:00:00] main() начался
# [12:00:00] После вызова slow_operation()
# Заметь: "Операция начала" НЕ печатается!
# slow_operation() никогда не выполнилась!
asyncio.run(main())
Проблемы в реальном коде
Проблема 1: Потеря данных
async def save_to_database(user_data: dict):
await asyncio.sleep(1) # Имитация запроса БД
print(f"Пользователь {user_data[name]} сохранён")
async def register_user(name: str):
user = {"name": name, "email": f"{name}@example.com"}
# БЕЗ await — функция не выполнится!
save_to_database(user) # ❌ НЕПРАВИЛЬНО
return f"Пользователь {name} зарегистрирован"
async def main():
result = await register_user("John")
print(result) # Пользователь John зарегистрирован
# Но в БД НИЧЕГО не сохранилось!
# Печать "Пользователь ... сохранён" не появится
asyncio.run(main())
Внешне всё выглядит нормально, но данные потеряны.
Проблема 2: RuntimeWarning о ненераспределённой корутине
async def async_task():
await asyncio.sleep(1)
return "Done"
async def main():
async_task() # ❌ Забыли await
# Вывод:
# RuntimeWarning: coroutine async_task was never awaited
asyncio.run(main())
Python предупреждает, что корутина никогда не была выполнена.
Проблема 3: Race conditions с несколькими задачами
async def fetch_user(user_id: int):
await asyncio.sleep(1)
return {"id": user_id, "name": f"User {user_id}"}
async def fetch_multiple():
# БЕЗ await — создаём 3 корутины, но НЕ выполняем их
user1 = fetch_user(1)
user2 = fetch_user(2)
user3 = fetch_user(3)
print(type(user1)) # <class coroutine>
# Возвращаем объекты, а не данные!
return [user1, user2, user3] # ❌ НЕПРАВИЛЬНО
async def main():
result = await fetch_multiple()
print(result) # [<coroutine...>, <coroutine...>, <coroutine...>]
# Данные НЕ получены!
asyncio.run(main())
Правильные способы
Способ 1: Простой await
async def main():
result = await fetch_user(1)
print(result) # Данные получены
Способ 2: asyncio.gather() для нескольких задач
async def main():
# Правильно: все задачи выполняются параллельно
results = await asyncio.gather(
fetch_user(1),
fetch_user(2),
fetch_user(3)
)
print(results) # [user1_data, user2_data, user3_data]
Способ 3: asyncio.create_task() для фоновых задач
async def background_task():
await asyncio.sleep(5)
print("Фоновая задача выполнена")
async def main():
# Создаём задачу БЕЗ ожидания
task = asyncio.create_task(background_task())
print("Main продолжает работу")
# Но позже нужно дождаться завершения!
await task
Способ 4: Проверка типа перед использованием
import asyncio
from inspect import iscoroutine
async def my_func():
return "Done"
async def main():
result = my_func() # Корутина
# Проверяем тип
if iscoroutine(result):
result = await result # Если корутина — await-им
print(result)
asyncio.run(main())
Ошибки типа TypeChecker
# mypy может поймать такие ошибки (если включена проверка)
async def async_func() -> int:
return 42
async def main() -> None:
result = async_func() # mypy error: Coroutine type expected
# mypy скажет: "Забыл await?"
Отличие Coroutine от Task
async def my_async():
return "result"
async def main():
# Coroutine — объект, который может быть выполнен
coro = my_async()
# Task — Coroutine, который уже был запланирован
task = asyncio.create_task(my_async())
# Task начнёт выполняться сразу (в следующем событии цикла)
# Coroutine выполнится только когда его await-иш
Как это связано с FastAPI
from fastapi import FastAPI
from sqlalchemy import select
app = FastAPI()
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# Если БЕЗ await
user = fetch_user_from_db(user_id) # ❌ Забыли await!
# user будет Coroutine, а не данные!
return user # Вернём некорректный объект
# Клиент получит:
# {"detail": "Object of type coroutine is not JSON serializable"}
Итоговый чек-лист
# ✓ Правильно: используй await для всех async функций
result = await async_function()
# ✓ Правильно: используй asyncio.gather() для параллельных задач
results = await asyncio.gather(task1(), task2(), task3())
# ✓ Правильно: используй asyncio.create_task() для фоновых задач
task = asyncio.create_task(background_work())
# ❌ НЕПРАВИЛЬНО: забыли await
result = async_function()
# ❌ НЕПРАВИЛЬНО: забыли await перед gather
results = asyncio.gather(task1(), task2())
# ❌ НЕПРАВИЛЬНО: забыли await перед create_task
task = asyncio.create_task(background_work())
Золотое правило
Если видишь async def — всегда используй await при вызове!
Иное приводит к:
- Потере данных
- Race conditions
- RuntimeWarning
- Неопределённому поведению
- Трудноуловимым багам в production
Просто всегда помни: async функция без await = корутина, которая никогда не выполнится.