Ключевые слова async и await в Python: синтаксис и примеры
Ключевые слова async и await появились в синтаксисе языка Python в версии 3.5, вышедшей в 2015 году. В пояснении к предложению PEP 492, его автор написал, что внедрение async/await поможет сделать написание асинхронного, параллельного кода Python более простым, максимально приблизит асинхронное программирование к синхронному.
Получилось это или нет, давайте разберем более подробно. Но сначала выясним, зачем нужны ключевые слова async и await в Python, и в каком сценарии их можно применять.
Немного об асинхронном программировании
Ключевые слова async и await нужны для реализации асинхронности в Python. Благодаря им можно выполнять операции без блокировки основного потока выполнения приложения.
Асинхронное программирование создает условия, при которых выполнение заданий происходит параллельно, а не поочередно. То есть, порядок выполнения не столь важен, второе задание не дожидается завершения первого. Это может быть заметно при выполнении множества операций ввода-вывода (например при обработке пользовательских запросов). Таким образом, асинхронное программирование ускоряет работу всей программы поскольку более эффективно распределяет ресурсы.
Ключевое слово async нужно чтобы объявить асинхронную функцию. Она, в свою очередь, возвращает объект coroutine, который «ожидается» при участии await.
async def my_async_function(): print("Welcome") await asyncio.sleep(1) # Имитирует задержку print("Home")
Теперь поговорим про await. Это ключевое слово приостанавливает выполнение асинхронной функции до момента получения результата из другой асинхронной функции. Вместо того, чтобы блокировать поток, приложение переходит к выполнению иных задач. В итоге это улучшает производительность.
async def example(): await my_async_function() # Ожидаем выполнения coroutine
Что такое корутина (coroutine) в Python
Корутина (coroutine или сопрограмма) в языке программирования Python — это особый тип функции, который допускает приостановку и возобновление в какой-либо точке её выполнения. Этим сопрограмма отличается от привычных функций, выполнение которых происходит до конца. Еще одной особенностью сопрограмм является то, что с ней можно выполнять асинхронные и многозадачные операции внутри приложение без применения потоков или процессов. Иными словами, с сопрограммой можно писать асинхронный код, который похож на синхронный. Это делает приложение более удобочитаемой.
Сопрограмма приостанавливается с помощью ввода await. Это освобождает управление для работы других задач. Затем, когда данные готовы, уже не нужно ждать: выполнение возобновляется.
Как создать корутину? Для этого задания в Python есть ключевое слово async. Если его использовать перед определением функции, то функция возвращает объект coroutine. Затем его можно использовать для асинхронных задач. Пример создания корутины:
async def my_coroutine(): print("Start coroutine") await asyncio.sleep(1) print("End coroutine")
Как вызвать корутину? Корутина или сопрограмма — это не совсем обычная функция, поэтому ее нельзя вызвать напрямую. Вместо этого нужно использовать ключевое слово await, чтобы дождаться завершения её выполнения, либо запускать корутину с помощью таких конструкций, как asyncio.run(). Посмотрите на фрагмент кода:
import asyncio async def my_coroutine(): print("Welcome") await asyncio.sleep(1) # Имитирует задержку print("Home") asyncio.run(my_coroutine()) # Запускает корутину
Чем корутина отличается от генератора? Сопрограммы немного схожи на генераторы (использующие yield), но их задача состоит в работе сугубо с асинхронным кодом. К тому же в генераторах передача управления происходит обратно в основной код при каждом вызове yield, а в корутинах для этого применяется await.
Асинхронность и Awaitable object в Python
Использование преимуществ асинхронного программирования повышает эффективность операций ввода-вывода. Поскольку задачи работают в параллельном режиме (но в едином потоке), это сокращает время работы программ и ресурсы памяти.
Еще одной сферой использования ключевого слова await в Python является awaitable object (ожидаемый объект) — объект, который применяется внутри асинхронных функций. Предназначение подобных объектов в том, чтобы представлять операции, допускающие приостановку и возобновление без блокировки выполнения программы.
Типы ожидаемых объектов (awaitable objects):
- Корутины: Асинхронные функции, которые создаются через async def. Они возвращают корутину, которую можно «ожидать» с помощью await.
- Tasks (Задачи): Это своего рода обёртки вокруг корутин. При создании задачи с помощью asyncio.create_task(), возникает объект, который также является awaitable.
- Future (Будущие объекты): Это особые объекты, используемые для представления результата какой-либо будущей асинхронной операции. Встроенные библиотеки, такие как asyncio, предоставляют такие объекты для работы с событиями и результатами операций.
Пример программы на Python с использованием ключевых слов async и await
Чтобы легче понять преимущества асинхронного программирования, давайте напишем небольшую программу работы таймера, в коде которой присутствуют async и await.
import asyncio # Асинхронная функция для имитации таймера async def timer(name: str, seconds: int): print(f"Таймер {name} запущен на {seconds} секунд.") await asyncio.sleep(seconds) # Ожидание асинхронно print(f"Таймер {name} завершён.") # Основная асинхронная функция для запуска нескольких таймеров async def main(): # Запускаем три таймера параллельно await asyncio.gather( timer("A", 5), timer("B", 4), timer("C", 8) ) # Запуск асинхронного кода asyncio.run(main())
- В коде, показанном выше, мы видим функцию timer, находящуюся в режиме ожидания в течение указанного количества секунд.
- В функции main есть три таймера, которые запускаются одновременно с помощью asyncio.gather. Это позволяет им работать параллельно.
- Каждый таймер работает асинхронно, поэтому приложение не блокируется во время их ожидания.
Вывод:
Таймер A запущен на 5 секунд. Таймер B запущен на 4 секунды. Таймер C запущен на 8 секунд. Таймер B завершён. Таймер A завершён. Таймер C завершён.
Это простой пример, демонстрирующий работу с асинхронными задачами и управлением временем ожидания с использованием async и await.
Сообщить об опечатке
Текст, который будет отправлен нашим редакторам: