Ответ
async/await в Python решает проблему блокирующего ввода-вывода (I/O-bound операций) в однопоточном коде. Традиционный синхронный код блокирует выполнение всего потока во время ожидания операций ввода-вывода (например, сетевых запросов, чтения с диска), что приводит к неэффективному использованию ресурсов и низкой пропускной способности.
async/await позволяет писать асинхронный код, который выглядит как синхронный, но при этом кооперативно переключает контекст выполнения, когда встречается await для I/O-операции. Это достигается за счет цикла событий (event loop), который управляет очередью задач.
Ключевые преимущества:
- Неблокирующий I/O: Поток выполнения не блокируется во время ожидания I/O, позволяя выполнять другие задачи.
- Высокая производительность: Эффективно обрабатывает тысячи одновременных соединений (например, в веб-серверах) без создания множества потоков.
- Улучшенная читаемость: Асинхронный код становится более линейным и понятным по сравнению с колбэками.
- Эффективное использование ресурсов: Один поток может управлять множеством параллельных I/O-операций.
Пример (Python asyncio):
import asyncio
import time
async def fetch_data(delay: int, name: str) -> str:
"""Имитация долгого I/O запроса."""
print(f"Начинаем {name}...")
await asyncio.sleep(delay) # Имитация ожидания I/O
print(f"Закончили {name}.")
return f"Данные от {name}"
async def main():
start_time = time.monotonic()
# Запускаем две I/O-bound задачи параллельно
task1 = asyncio.create_task(fetch_data(2, "Сервер A"))
task2 = asyncio.create_task(fetch_data(1, "Сервер B"))
print("Делаем что-то другое, пока задачи выполняются...")
# Ожидаем завершения обеих задач
data1 = await task1
data2 = await task2
print(f"Получили: {data1}")
print(f"Получили: {data2}")
print(f"Общее время выполнения: {time.monotonic() - start_time:.2f} сек.")
if __name__ == "__main__":
asyncio.run(main())
В этом примере fetch_data имитирует сетевые запросы. Благодаря async/await и asyncio, обе задачи выполняются конкурентно в одном потоке, и общее время выполнения составляет около 2 секунд (время самой долгой задачи), а не 3 секунды, как было бы при последовательном выполнении.