Вернуться к статьям

Современная работа с асинхронным кодом на Python: asyncio на практике

Программирование 25.02.2026 3 просмотров

Ключевые слова

python asyncio асинхронность асинхронное программирование event loop await async разработка примеры советы
Современная работа с асинхронным кодом на Python: asyncio на практике

Асинхронное программирование становится всё более востребованным в современных проектах на Python, особенно там, где нужно обслуживать множество одновременных запросов или задач с задержками — обработка сетевых соединений, API, чаты, веб-сервисы, парсеры, боты и другое. В статье разбираем суть асинхронности, быстрый старт с asyncio, типовые паттерны и шаги внедрения, а также подводные камни и рекомендации из практики.

Зачем нужен асинхронный код: основные сценарии применения

Стандартная синхронная модель Python проста, но неэффективна при большом числе операций, связанных с ожиданием: сетевые вызовы, задержки, ввод-вывод. Именно здесь асинхронность даёт значительный прирост производительности за счёт неблокирующего ожидания и параллельного выполнения задач в рамках одного потока.

Когда асинхронность особенно полезна

  • Веб-сервисы, обрабатывающие множество одновременных HTTP-запросов (FastAPI, Aiohttp)
  • Боты и парсеры, массово обращающиеся к внешним API
  • Работа с сетевыми протоколами, сокетами, WebSocket
  • Проекты с большим количеством задач, ожидающих файл, сеть, БД

С помощью asyncio в Python можно обрабатывать тысячи соединений и процессов без масштабирования на дополнительные потоки или процессы.

Основы asyncio: корутины, event loop, await

Основные строительные блоки асинхронного кода в Python — корутины (async def), цикл событий (event loop) и оператор await.

Минимальный рабочий пример

import asyncio

async def say_hello():
    print('Привет!')
    await asyncio.sleep(1)
    print('Прошла одна секунда.')

async def main():
    await say_hello()

asyncio.run(main())

Здесь async def определяет корутину. Внутри используем await — выполнение приостанавливается на асинхронной операции (asyncio.sleep), давая возможность другим задачам выполняться в это время.

Запуск нескольких задач параллельно

Асинхронность позволяет запускать несколько задач одновременно на одном потоке без использования потоков или процессов.

async def task(num):
    print(f'Задача {num} стартовала')
    await asyncio.sleep(num)
    print(f'Задача {num} завершилась')

async def main():
    # Параллельный запуск трех задач
    await asyncio.gather(*(task(i) for i in range(1, 4)))

asyncio.run(main())

Все три задачи стартуют почти одновременно, но завершаются по мере окончания ожидания (sleep).

Пошаговое внедрение асинхронности: инструкция для проекта

  1. Проанализируйте код: Определите критичные части приложения с I/O операциями — запросы к сети, файлам, БД, сторонним сервисам.
  2. Проверьте совместимость: Не все сторонние библиотеки поддерживают асинхронные вызовы. Ищите аналоги с Async API (например, aiohttp вместо requests).
  3. Переопределите функции как async def: Это позволит использовать await для неблокирующих операций.
  4. Замените блокирующие вызовы: Вместо time.sleepawait asyncio.sleep; вместо requests.getawait aiohttp.get и т.п.
  5. Организуйте запуск через asyncio.run и используйте asyncio.gather для параллельной работы корутин.
  6. Протестируйте и профилируйте: Убедитесь, что асинхронная логика действительно ускоряет I/O и не приводит к ошибкам.

Пример применения: массовые асинхронные запросы к API

import aiohttp
import asyncio

async def fetch(url, session):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = ['https://example.com', 'https://python.org', 'https://github.com']
    async with aiohttp.ClientSession() as session:
        results = await asyncio.gather(*(fetch(url, session) for url in urls))
        for text in results:
            print('Получено строк:', len(text))

asyncio.run(main())

Здесь все запросы выполняются асинхронно – итоговое время выполнения близко к длительности самого медленного запроса, а не их сумме.

Типичные ошибки и лучшие практики работы с asyncio

Частые ошибки новичков

  • Смешивание синхронного и асинхронного кода: Если в асинхронной корутине вызывается синхронная (блокирующая) функция — это «останавливает» event loop и нивелирует преимущество.
  • Повторный запуск event loop: Вызов asyncio.run внутри уже запущенного event loop приводит к ошибке. В таких случаях используйте await или asyncio.create_task внутри корутин.
  • Неправильное управление жизнью ресурса: Не закрыт ClientSession (aiohttp) или соединение — утечки памяти, ошибки соединения.

Рекомендации для «боевого» кода

  • Чётко разграничивайте асинхронные и синхронные функции
  • Используйте асинхронные аналоги сторонних библиотек
  • Обрабатывайте ошибки (например, asyncio.TimeoutError) с помощью try/except внутри корутин
  • Профилируйте загрузку и масштабируйте (например, ограничивайте число одновременных задач с помощью asyncio.Semaphore)

Пример с семафором: ограничение количества параллельных задач

sem = asyncio.Semaphore(5)  # не более 5 одновременных задач

async def limited_task(url, session):
    async with sem:
        return await fetch(url, session)

Заключение

Асинхронное программирование на Python — не модная тенденция, а необходимый навык для разработки современных быстрых приложений. Технология asyncio позволяет существенно экономить ресурсы, оптимизировать обработку I/O и масштабировать серверную логику. Освойте базовые паттерны (async/await, gather, асинхронные веб-клиенты) и применяйте асинхронность там, где это критично для производительности, не забывая о практике и безопасности ресурсов. Начните с малого — попробуйте переписать свою функцию под асинхронный стиль — и почувствуйте разницу!