Ответ
До появления ключевых слов async
/await
в Python 3.5, асинхронность на базе asyncio
реализовывалась с помощью генераторов и специального декоратора.
Основными инструментами были:
- Декоратор
@asyncio.coroutine
: Он помечал функцию-генератор как корутину, совместимую с циклом событийasyncio
. - Выражение
yield from
: Использовалось вместо современногоawait
для передачи управления другой корутине и ожидания её результата.
По сути, async def
является синтаксическим сахаром над генераторами, а await
— над yield from
.
Сравнение синтаксиса:
Старый стиль (Python 3.4):
import asyncio
@asyncio.coroutine
def old_style_fetch_data(url):
print(f"Fetching {url}...")
# Вместо await используется yield from
response = yield from asyncio.sleep(1) # Имитация сетевого запроса
print(f"Done fetching {url}.")
return {"data": f"Some data from {url}"}
loop = asyncio.get_event_loop()
loop.run_until_complete(old_style_fetch_data("https://example.com"))
Современный стиль (Python 3.5+):
import asyncio
async def new_style_fetch_data(url):
print(f"Fetching {url}...")
# Используется async/await
await asyncio.sleep(1)
print(f"Done fetching {url}.")
return {"data": f"Some data from {url}"}
asyncio.run(new_style_fetch_data("https://example.com"))
Основной недостаток старого подхода заключался в том, что синтаксически корутины не отличались от обычных генераторов, что могло приводить к путанице. Введение async
/await
сделало асинхронный код более явным и читаемым.