Введение в асинхронность: async/await, event loop
🚀 Почему асинхронность — это круто?
Представь: твой код делает запрос к серверу, но вместо простоя в ожидании ответа он параллельно обрабатывает другие задачи. 📡➡️💻 Это и есть асинхронность — способность выполнять операции без блокировки потока.
Пример из жизни:
- Синхронный подход — как кассир, который обслуживает одного клиента, а остальные стоят в очереди.
- Асинхронный подход — кассир принимает заказы у всех, а пока еда готовится, переключается на новых клиентов.
В Python за это отвечают три кита:
async/await— ключевые слова для описания асинхронных функций- Event Loop — диспетчер, управляющий выполнением задач
- Корутины (coroutines) — специальные функции, которые могут приостанавливаться
🛠️ Основы: async и await
Корутины — сердце асинхронности
import asyncio
async def brew_coffee():
print("Начинаем готовить кофе...")
await asyncio.sleep(3) # Имитация долгой операции
print("Кофе готов!")
return "Капучино"
# Запуск корутины
result = asyncio.run(brew_coffee())
print(f"Результат: {result}")
🔹 async — объявляет асинхронную функцию (корутину).
🔹 await — точка "разрыва", где функция приостанавливается, пока операция не завершится.
⚠️ Важно: await можно использовать только внутри async-функций!
🔄 Event Loop: как это работает?
Event Loop — это бесконечный цикл, который:
1. Получает задачи (корутины)
2. Выполняет их до первого await
3. Переключается на другие задачи, пока первые "ждут"
4. Возвращается к завершённым задачам

async def task_one():
print("Задача 1 началась")
await asyncio.sleep(2)
print("Задача 1 завершена")
async def task_two():
print("Задача 2 началась")
await asyncio.sleep(1)
print("Задача 2 завершена")
async def main():
await asyncio.gather(task_one(), task_two()) # Запуск параллельно
asyncio.run(main())
Вывод:
Задача 1 началась
Задача 2 началась
Задача 2 завершена
Задача 1 завершена
⚡ Практика: асинхронный HTTP-клиент
Используем библиотеку aiohttp для реального примера:
import aiohttp
import asyncio
async def fetch_url(url):
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
urls = [
"https://python.org",
"https://github.com",
"https://youtube.com"
]
# Запускаем все запросы параллельно
pages = await asyncio.gather(*[fetch_url(url) for url in urls])
print(f"Получено {len(pages)} страниц")
# Точка входа
asyncio.run(main())
🔍 Разбор:
ClientSession— асинхронный аналогrequests.Session()- Каждый
awaitпозволяет переключаться между запросами asyncio.gather— запуск задач "веером"
🧠 Глубокое погружение: как избежать ошибок?
Топ-3 подводных камня
1. Блокирующие вызовы
Никогда не используйте time.sleep() внутри async функций — это блокирует весь поток!
# Плохо:
time.sleep(1) # Блокирует весь поток!
# Хорошо:
await asyncio.sleep(1)
2. Бесконечные корутины
Всегда ограничивайте время выполнения длительных операций:
await asyncio.wait_for(slow_operation(), timeout=5)
3. Неправильное создание задач
Не забывайте про asyncio.create_task() для запуска фоновых операций:
async def background_task():
await asyncio.sleep(10)
async def main():
task = asyncio.create_task(background_task())
# Основная работа...
await task
🏆 Главные выводы
- Асинхронность ≠ многопоточность — это кооперативная многозадачность
- Event Loop управляет выполнением корутин через
await - Библиотеки типа
aiohttpиasyncpgиспользуют эти принципы - Всегда проверяйте, что код не содержит блокирующих вызовов
Для полного погружения рекомендую курс Данилы Бежина по продвинутому Python — там разбираются реальные кейсы!