Введение в асинхронность: async/await, event loop

🚀 Почему асинхронность — это круто?

Представь: твой код делает запрос к серверу, но вместо простоя в ожидании ответа он параллельно обрабатывает другие задачи. 📡➡️💻 Это и есть асинхронность — способность выполнять операции без блокировки потока.

Пример из жизни:

  • Синхронный подход — как кассир, который обслуживает одного клиента, а остальные стоят в очереди.
  • Асинхронный подход — кассир принимает заказы у всех, а пока еда готовится, переключается на новых клиентов.

В Python за это отвечают три кита:

  1. async/await — ключевые слова для описания асинхронных функций
  2. Event Loop — диспетчер, управляющий выполнением задач
  3. Корутины (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. Возвращается к завершённым задачам

Визуализация Event Loop

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())

🔍 Разбор:

  1. ClientSession — асинхронный аналог requests.Session()
  2. Каждый await позволяет переключаться между запросами
  3. 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

🏆 Главные выводы

  1. Асинхронность ≠ многопоточность — это кооперативная многозадачность
  2. Event Loop управляет выполнением корутин через await
  3. Библиотеки типа aiohttp и asyncpg используют эти принципы
  4. Всегда проверяйте, что код не содержит блокирующих вызовов

Для полного погружения рекомендую курс Данилы Бежина по продвинутому Python — там разбираются реальные кейсы!

Скрыть рекламу навсегда

📘 VK Видео — обучение без ограничений

Все уроки доступны без VPN, без блокировок и зависаний.

Можно смотреть с телефона, планшета или компьютера — в любое время.

▶️ Смотреть на VK Видео