Принципы работы с async/await в Python: практическое руководство с примерами

03.03.25

Разработка - Языки и среды

В статье рассматриваются принципы работы с асинхронным программированием в Python с использованием async/await. На практических примерах показано, как создавать и управлять асинхронными задачами, использовать ключевые методы модуля asyncio, такие как create_task, gather, wait_for, и избегать распространённых ошибок. Материал будет полезен разработчикам, которые хотят улучшить производительность своих приложений за счёт асинхронного выполнения операций.

Асинхронное программирование в Python с использованием async/await позволяет эффективно выполнять задачи, связанные с операциями ввода-вывода (IO), такие как работа с сетью, файлами или базами данных. В этой статье мы рассмотрим основные принципы работы с async/await на практических примерах, а также изучим ключевые методы модуля asyncio.

Рассмотрим принципы работы с async/await на практических примерах. Для начала рассмотрим базовый пример асинхронной функции, которая имитирует загрузку данных с разных URL:

 
 простой пример асинхронного кода
import asyncio

async def fetch_data(url):
    await asyncio.sleep(1)
    return f"Данные с {url}"

async def main():
    # Параллельное создание задач
    task1 = asyncio.create_task(fetch_data("site1.com"))
    task2 = asyncio.create_task(fetch_data("site2.com"))
    
    # Ждём результатов обоих задач одновременно
    result1, result2 = await asyncio.gather(task1, task2)
    
    print(result1)
    print(result2)

# Запуск
# asyncio.run(main())

 

 Теперь рассмотрим

 
 параллельное выполнение асинхронных операций

Для лучшего понимания потока выполнения асинхронного кода, рассмотрим рисунок последовательности: 

import asyncio

async def fetch_data(url):
    await asyncio.sleep(1)
    return f"Данные с {url}"

async def main():
    # Параллельное создание задач
    task1 = asyncio.create_task(fetch_data("site1.com"))
    task2 = asyncio.create_task(fetch_data("site2.com"))
    
    # Ждём результатов обоих задач одновременно
    result1, result2 = await asyncio.gather(task1, task2)
    
    print(result1)
    print(result2)

# Запуск
# asyncio.run(main())

Рассмотрим подробнее, что происходит:

1. Создание задачи

Главная программа создаёт две задачи одновременно, не дожидаясь завершения первой

2. Параллельное выполнение

Обе задачи выполняются независимо друг от друга, каждая ожидает по 1 секунде

3. Обработка результата

После завершения обеих задач их результаты собираются через asyncio.gather()

Для лучшего понимания преимуществ async/await, сравним синхронный и асинхронный подходы:

 

Характеристика Синхронный код Асинхронный код (async/await)
Выполнение операций Последовательное, блокирующее Параллельное, неблокирующее
Использование CPU
Ожидание операции занимает ресурсы
Время ожидания используется для других задач
Сложность кода Простой, линейный Немного сложнее, но читаемый
Масштабируемость Ограниченная Высокая при работе с IO операциями

 

Основные преимущества async/await:

  1. Эффективность:
    • Одновременное выполнение нескольких операций
    • Оптимальное использование системных ресурсов
    • Быстрое выполнение IO-операций
  2. Читаемость кода:
    • Синтаксис близок к обычному синхронному коду
    • Логика выполнения более очевидна
    • Проще поддерживать и модифицировать
  3. Масштабируемость:
    • Легко добавлять новые асинхронные операции
    • Удобно управлять параллельным выполнением
    • Простая обработка ошибок через try-except

Для практического применения важно помнить:

  • Используйте async/await для IO-операций (сеть, файлы, базы данных)
  • Комбинируйте задачи с помощью asyncio.gather() для параллельного выполнения
  • Обрабатывайте ошибки в каждой асинхронной функции отдельно
  • Не используйте async/await для вычислительных задач без IO операций

Такой подход позволяет создавать эффективные и масштабируемые приложения с минимальными изменениями в структуре кода.

Давайте рассмотрим основные полезные процедуры модуля asyncio и их практическое применение.

 

Основные методы управления задачами

 
 1. create_task() - создание независимых задач
 
 2. gather() - параллельное выполнение задач
 
3. wait_for() - выполнение с таймаутом
 
 4. wait() - ожидание нескольких задач
 
 5. Queue - асинхронная очередь
 
 6. Semaphore - ограничение параллельных операций
 
 7. Структура асинхронного приложения
 
 8. Управление задачами
 
 9. Работа с ресурсами
 
 10. Обработка ошибок

Рекомендации по использованию

  1. Логирование:
    • Всегда используйте именованные логгеры
    • Логируйте ошибки с контекстом
    • Используйте разные уровни логирования (INFO, WARNING, ERROR)
  2. Управление ресурсами:
    • Используйте контекстные менеджеры (async with)
    • Всегда очищайте ресурсы в блоке finally
    • Используйте семафоры для ограничения параллельных операций
  3. Обработка ошибок:
    • Обрабатывайте специфические исключения
    • Используйте return_exceptions в gather
    • Логируйте ошибки с контекстом
  4. Таймауты:
    • Устанавливайте разумные таймауты для операций
    • Обрабатывайте TimeoutError
    • Отменяйте задачи при таймауте
  5. Именование задач:
    • Давайте осмысленные имена задачам
    • Используйте name параметр в create_task
    • Это помогает в отладке и мониторинге

Анти-паттерны, которых следует избегать

 
 1. Небезопасное создание зада
 
 2. Неправильная обработка ошибок
 
 3. Нарушение иерархии ресурсов

 

Заключение

Асинхронное программирование с использованием async/await позволяет создавать высокопроизводительные и масштабируемые приложения. Правильное использование методов модуля asyncio и соблюдение рекомендаций помогут избежать распространённых ошибок и улучшить качество кода.

Эта статья поможет вам освоить асинхронное программирование в Python и эффективно применять его в своих проектах.

Вступайте в нашу телеграмм-группу Инфостарт

async/await asyncio асинхронное программирование Python create_task gather wait_for семафоры асинхронные очереди обработка ошибок таймауты масштабируемость IO-операции.

См. также

Языки и среды Программист 1С v8.3 Бесплатно (free)

Будем писать свои скрипты на питоне и запускать их на 1С.

15.04.2024    7261    YA_418728146    14    

65

Языки и среды Программист Стажер 1С v8.3 Бесплатно (free)

Существует множество языков программирования, и каждый имеет свои особенности по работе с типами данных. Слабые, явные, динамические и другие... Но кто же здесь 1С и почему с приходом "строгой" типизации EDT 1С-программистам стоит задуматься над изменением своих привычек.

16.01.2024    10993    SeiOkami    25    

64

Языки и среды Программист Бесплатно (free)

Пример небольшого приложения, с которого можно начать изучать язык программирования Dart.

08.08.2023    5273    acvatoris    6    

15

Языки и среды Программист 1С v8.3 Россия Бесплатно (free)

Написание статического анализатора для 1С традиционным способом на Си.

30.06.2023    4190    prohorp    15    

12

Языки и среды Программист Абонемент ($m)

Поставили нам задачу - вынести на отдельный сервер функционал получения заказов от клиентов по электронной почте, парсинг полученных XLS в приемлемый вид и трансформация заказов в красивый JSON, понятный нашей учетной системе на 1С. Всю эту красоту желательно запустить в отдельном докер - контейнере, по возможности не тратя лицензии, поэтому отдельно стоящую конфигурацию на БСП отвергаем сразу. Можно было бы собрать всё на Apache Airflow или Apache NiFi, но решили попробовать реализовать всю логику без Open Source, будем делать свой ETL, с Исполнителем, который в версии 3.0 научился взаимодействовать с электронной почтой по IMAP. Начнем с середины - сначала напишем скрипты, а потом соберем их в рабочую конструкцию

1 стартмани

01.06.2023    2896    0    kembrik    2    

11

Языки и среды Инструментарий разработчика Программист 1С v8.3 Абонемент ($m)

Вставки кода на C# внутри кода на 1С.

5 стартмани

07.04.2023    12003    4    SerVer1C    58    

46

Языки и среды Программист 1С v8.3 Бесплатно (free)

При работе с 1С ORM (object relation mapping) все время преследует ощущение постоянного создания монолитного приложения — один раз привязался к какой либо сущности (например, справочник Контрагенты), и весь код заполнен ссылками на эту конкретную реализацию. Можно ли независимо разрабатывать в ORM совместимые между собой справочник «Контрагентов» и использующий его документ «Платежное поручение», но при этом избежать жестких зависимостей? Спасут ли нас микросервисы? Пример на аннотациях Java демонстрирует, как это возможно делать.

13.03.2023    1661    1CUnlimited    0    

3

WEB-интеграция Языки и среды Программист 1С v8.3 Абонемент ($m)

Добавление в JS обозревателя 1Сных коллекций массив, структура и таблица значений. Строкование в json формат для обмена с 1Сным сервером.Убедимся, что в обозревателе 1Сные коллекции действительно работают через чтение, изменение и строкование объекта обратно в json строку.

10 стартмани

01.03.2023    3572    Steelvan    0    

5
Оставьте свое сообщение