Что такое await в Python

Ответ

await — это ключевое слово в Python, используемое в асинхронном программировании для приостановки выполнения текущей корутины (функции, объявленной с async def) до завершения другой "awaitable" операции. Это позволяет программе эффективно использовать время ожидания, не блокируя основной поток выполнения.

Почему await важен? В традиционном синхронном коде, когда функция выполняет долгую операцию (например, сетевой запрос, чтение файла), весь поток выполнения блокируется до её завершения. await решает эту проблему:

  • Неблокирующее ожидание: Когда корутина встречает await, она приостанавливает своё выполнение и передаёт управление обратно в цикл событий (event loop).
  • Конкурентность: Цикл событий может использовать это время для выполнения других задач, пока ожидаемая операция не завершится. Как только ожидаемая операция готова, цикл событий возобновляет выполнение приостановленной корутины. Это позволяет эффективно обрабатывать множество I/O-связанных задач одновременно, значительно улучшая отзывчивость и пропускную способность приложений.

Пример использования:

import asyncio

async def fetch_data(delay: int, name: str) -> str:
    """Имитирует асинхронную загрузку данных."""
    print(f"[{name}] Начало загрузки данных (ожидание {delay} сек)...")
    await asyncio.sleep(delay)  # Приостановка выполнения, управление передаётся event loop
    print(f"[{name}] Данные загружены.")
    return f"Результат от {name}"

async def main():
    print("Запуск основной программы.")
    # Запускаем две задачи конкурентно
    task1 = asyncio.create_task(fetch_data(2, "Задача 1"))
    task2 = asyncio.create_task(fetch_data(1, "Задача 2"))

    # Ожидаем завершения обеих задач
    result1 = await task1
    result2 = await task2

    print(f"Получено: {result1}")
    print(f"Получено: {result2}")
    print("Основная программа завершена.")

if __name__ == "__main__":
    asyncio.run(main())

Вывод при выполнении:

Запуск основной программы.
[Задача 1] Начало загрузки данных (ожидание 2 сек)...
[Задача 2] Начало загрузки данных (ожидание 1 сек)...
[Задача 2] Данные загружены.
[Задача 1] Данные загружены.
Получено: Результат от Задача 1
Получено: Результат от Задача 2
Основная программа завершена.

Обратите внимание, что "Задача 2" завершилась раньше, хотя "Задача 1" была запущена первой. Это демонстрирует неблокирующий характер await.

Ключевые особенности:

  • Только внутри async def: await может быть использован только внутри функций, объявленных с async def.
  • Ожидание "awaitable" объектов: await может ожидать корутины, объекты Future, или другие объекты, реализующие протокол awaitable (например, asyncio.sleep()).
  • Возврат корутины: Если вы забудете использовать await перед вызовом async def функции, она не выполнится, а просто вернёт объект корутины. Это частая ошибка, которая может привести к незаметным багам.
  • Не блокирует поток: await не блокирует операционную систему или поток выполнения, а лишь приостанавливает текущую корутину, позволяя циклу событий переключиться на другие задачи.

Ответ 18+ 🔞

Слушай, а вот этот твой await, он вообще кто такой, сука? Ну, типа, ключевое слово в Питоне, да? Ну, для этих самых асинхронных штук, где всё бегает, не дожидаясь друг друга, как охуевшие тараканы.

А нахуя он вообще нужен, этот await? Представь, ты в синхронном коде, как лох, ждёшь, пока файл скачается или запрос на сервер уйдёт. Весь твой код, блядь, встал колом, как будто его в рот ебнули, и ждёт. А await — это как хитрая жопа: он говорит «стоп, я тут подожду», но при этом отпускает управление обратно в этот самый цикл событий (event loop, ёпта).

  • Неблокирующее ожидание, блядь: Коротышка-корутина упирается в await, говорит «я пас», и цикл событий идёт делать другие дела.
  • Конкурентность, ёбана: Пока одна задача тупит, другие могут работать. Это ж овердохуища эффективно для всяких сетевых запросов, где 99% времени — это просто ждать, блядь.

Смотри, как это выглядит в деле:

import asyncio

async def fetch_data(delay: int, name: str) -> str:
    """Имитирует асинхронную загрузку данных."""
    print(f"[{name}] Начало загрузки данных (ожидание {delay} сек)...")
    await asyncio.sleep(delay)  # Вот тут она приостановится, а не зависнет нахуй!
    print(f"[{name}] Данные загружены.")
    return f"Результат от {name}"

async def main():
    print("Запуск основной программы.")
    # Запускаем две задачи конкурентно
    task1 = asyncio.create_task(fetch_data(2, "Задача 1"))
    task2 = asyncio.create_task(fetch_data(1, "Задача 2"))

    # Ожидаем завершения обеих задач
    result1 = await task1
    result2 = await task2

    print(f"Получено: {result1}")
    print(f"Получено: {result2}")
    print("Основная программа завершена.")

if __name__ == "__main__":
    asyncio.run(main())

И что на выходе, блядь?

Запуск основной программы.
[Задача 1] Начало загрузки данных (ожидание 2 сек)...
[Задача 2] Начало загрузки данных (ожидание 1 сек)...
[Задача 2] Данные загружены.
[Задача 1] Данные загружены.
Получено: Результат от Задача 1
Получено: Результат от Задача 2
Основная программа завершена.

Видишь, ёпта? Вторая задача, которая на секунду, управилась быстрее, хотя запустили их почти вместе. Потому что первая, болван, уснула на две секунды с await, а в это время вторая спокойно своё дело сделала. Красота, блядь!

Важные моменты, а то опять наебнёшься:

  • Только в async def: Этот await работает только внутри функций, которые объявил как async def. Снаружи него — нихуя.
  • Ждёт «ожидаемое»: Он может ждать корутину, Future или что-то ещё, что умеет говорить «я готов». Как asyncio.sleep().
  • Возвращает корутину, если забыть: Вот это, блядь, классика! Если вызвать async def функцию без await перед ней, она нихуя не выполнится, а просто вернёт тебе объект корутины. И ты потом будешь чесать репу, почему ничего не работает. Сам от себя охуеешь.
  • Не блокирует поток: Он не вешает всю операционку, он просто тихо приостанавливает одну мелкую корутину, чтобы цикл событий мог переключиться на других. Умно, сука!