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

Пишем поддержку асинхронности в Python-проектах: как и зачем начать использовать asyncio

Программирование 19.02.2026 1 просмотров

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

python асинхронное программирование asyncio event loop async await параллелизм производительность ввод-вывод примеры кода советы
Пишем поддержку асинхронности в Python-проектах: как и зачем начать использовать asyncio

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

Когда актуальна асинхронность: критерии для внедрения

Асинхронное программирование не всегда обязательно, но в ряде случаев оно предоставляет значительные преимущества. Вот главные ситуации, когда стоит задуматься о внедрении asyncio:

  • Блокирующие операции ввода-вывода — частые запросы к базе данных, сетевые обращения (API, веб-сервисы), файловые операции.
  • Высокая нагрузка — серверные приложения, веб-приложения, микросервисы, которые должны обслуживать десятки и сотни одновременных запросов.
  • Реализация долгоживущих фоновых задач — слушатели очередей, парсеры, боты и прочие сервисы, работающие в режиме ожидания событий.

Для вычислительно тяжёлых задач (числовая обработка, рендеринг, машинное обучение) традиционная асинхронность на Python малоэффективна из-за ограничений GIL, в таких случаях эффективнее multiprocessing или сторонние решения.

Базовые концепции AsyncIO: асинхронные функции, event loop и корутины

Что такое event loop

Event loop (цикл событий) — это сердце асинхронного приложения. Он отвечает за выполнение корутин и обработку событий. Вместо традиционного ожидания завершения результата (блокировки), реализуется система коллбеков, позволяющая переключаться между задачами в режиме ожидания I/O буквально "на лету".

Асинхронные функции и ключевые слова async/await

  • async def — объявляет функцию как асинхронную (корутину).
  • await — "приостанавливает" выполнение корутины до получения результата другой асинхронной операции.
import asyncio

async def fetch_data():
    await asyncio.sleep(1)
    return 'Данные получены'

async def main():
    result = await fetch_data()
    print(result)

asyncio.run(main())

В этом примере asyncio.sleep(1) имитирует задержку I/O (например, сетевой запрос). В момент ожидания можно выполнять другие задачи, не блокируя поток.

Как начать использовать asyncio: первые шаги и простые паттерны

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

  1. Выделите блокирующие участки кода: определите функции, которые занимаются длительным ожиданием данных — они станут кандидатами на переписывание под async.
  2. Рефакторите функции: преобразуйте их в асинхронные (async def), используйте await для вызовов асинхронных библиотек или методов (например, aiohttp вместо requests).
  3. Обновите вызовы: все вызывающие функции тоже должны быть асинхронными, либо использовать asyncio.run или loop.run_until_complete.

Пример: параллельные запросы с asyncio и aiohttp

import asyncio
import aiohttp

urls = [
    'https://python.org',
    'https://www.google.com',
    'https://www.github.com'
]

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

async def main():
    async with aiohttp.ClientSession() as session:
        tasks = [fetch(session, url) for url in urls]
        responses = await asyncio.gather(*tasks)
        print([len(r) for r in responses])

asyncio.run(main())

Этот пример выполняет три HTTP-запроса параллельно за время, близкое к длительности самого долгого из них — в синхронном варианте это бы заняло в 3 раза больше времени.

Типовые ловушки и рекомендации

  • Не блокируйте event loop! — избегайте вызова блокирующих библиотек (например, стандартных requests и time.sleep), если работаете в async коде.
  • Внешние библиотеки: всегда ищите асинхронные аналоги (например, aiomysql, aioredis).
  • Переход делайте постепенно — начните с небольших, изолированных функций, протестируйте их отдельно.
  • Обработка ошибок: используйте try/except внутри корутин, чтобы не терять сообщения об ошибках и не "рассыпать" event loop.

Асинхронность в продакшене: система работы и лучшие практики

Тестирование асинхронного кода

Для тестирования асинхронных функций используйте pytest-asyncio или встроенные возможности pytest для поддержки async/await:

import pytest
import asyncio

@pytest.mark.asyncio
async def test_fetch():
    result = await fetch_data()
    assert result == 'Данные получены'

Мониторинг и дебаггинг

  • Профилируйте асинхронные функции с помощью asyncio.Task.all_tasks() и сторонних дебаггеров (например, aiomonitor).
  • Используйте asyncio debug mode (PYTHONASYNCIODEBUG=1) для отслеживания медленных колбеков и обнаружения "зависших" корутин.

Какие библиотеки поддерживают асинхронность

  • aiohttp — HTTP-клиент/сервер для асинхронных запросов.
  • aiomysql, aiopg — работа с базами данных MySQL/Postgres.
  • asyncpg — высокопроизводительный драйвер для PostgreSQL.
  • aioredis — асинхронная работа с Redis.
  • FastAPI, Sanic, Quart — асинхронные веб-фреймворки для API и серверов.

Заключение

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