JavaRush /Курсы /Модуль 1: Python Core /Асинхронные контекстные менеджеры

Асинхронные контекстные менеджеры

Модуль 1: Python Core
14 уровень , 8 лекция
Открыта

9.1 Контекстные менеджеры

Вы помните, как мы использовали оператор with, чтобы контролировать доступ к ресурсу? С его помощью можно было точно отследить, когда ресурс начал использоваться, и когда этот процесс закончился. То же самое можно делать и для «асинхронных ресурсов».

Асинхронные контекстные менеджеры (AsyncContextManager) используются для управления ресурсами в асинхронном программировании, обеспечивая правильное открытие и закрытие ресурсов в асинхронных функциях. Они работают аналогично обычным контекстным менеджерам, но предназначены для использования в асинхронных функциях с ключевыми словами async with.

Я не буду подробно про это рассказывать, так как в ближайшее время вы точно не будете создавать свои асинхронные контекстные менеджеры, а к тому времени, когда решите это делать, всё равно всё забудете. Но познакомить с самой концепцией я вас хочу.

Создание асинхронного контекстного менеджера

Асинхронные контекстные менеджеры определяются с использованием методов __aenter__ и __aexit__. Эти методы аналогичны методам __enter__ и __exit__ в обычных контекстных менеджерах, но являются асинхронными.

  • __aenter__(): Асинхронный метод, вызываемый при входе в контекст.
  • __aexit__(exc_type, exc, tb): Асинхронный метод, вызываемый при выходе из контекста. Принимает три аргумента: тип исключения, само исключение и трассировку (traceback).

Пример создания асинхронного контекстного менеджера


import asyncio

class AsyncContextManager:
    async def __aenter__(self):
        print("Enter context")
        return self
        
    async def __aexit__(self, exc_type, exc, tb):
        print("Exit context")
        
async def main():
    async with AsyncContextManager():
        print("Inside context")
        
asyncio.run(main())

Вот как будет выполняться этот код:

  1. Асинхронно запустится функция main().
  2. Функция main() начнёт выполняться.
  3. Создастся объект типа AsyncContextManager.
  4. У объекта AsyncContextManager вызовется метод __aenter__().
  5. Выведется print("Enter context").
  6. Выполнится код print("Inside context").
  7. У объекта AsyncContextManager вызовется метод __aexit__().
  8. Завершится выполнение функции main().

9.2 Примеры использования

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

Но асинхронный менеджер нужен, если внутри блока with вызывается асинхронная функция или используется оператор await.

Асинхронный контекстный менеджер для работы с файлами

В этом примере используется библиотека aiofiles для асинхронного чтения и записи файлов. Асинхронный контекстный менеджер aiofiles.open позволяет безопасно открывать и закрывать файлы в асинхронном контексте.


import aiofiles
import asyncio
            
async def main():
    async with aiofiles.open('example.txt', mode='w') as file:
        await file.write('Hello, world!')
            
asyncio.run(main())

Асинхронный контекстный менеджер для сетевых операций

В этом примере используется библиотека aiohttp для выполнения асинхронных HTTP-запросов. Асинхронные контекстные менеджеры ClientSession и session.get обеспечивают правильное управление соединениями.


import aiohttp
import asyncio
            
async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()
            
async def main():
    html = await fetch('https://example.com')
    print(html)
            
asyncio.run(main())

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

Методы __aenter__ и __aexit__ позволяют выполнять асинхронные операции при входе и выходе из контекста, обеспечивая параллельное выполнение задач. Использование асинхронных контекстных менеджеров помогает избежать утечек ресурсов и гарантирует, что все ресурсы будут корректно освобождены.

2
Задача
Модуль 1: Python Core, 14 уровень, 8 лекция
Недоступна
Асинхронный контекстный менеджер
Асинхронный контекстный менеджер
2
Задача
Модуль 1: Python Core, 14 уровень, 8 лекция
Недоступна
АКМ для работы с файлами
АКМ для работы с файлами
Комментарии (3)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Виталий Уровень 33
14 июля 2025
В примерах явно хочется комментариев. Например:

# Импортируем библиотеку для асинхронных HTTP-запросов
import aiohttp
# Импортируем библиотеку для асинхронного программирования
import asyncio

# Определяем асинхронную функцию для выполнения HTTP-запроса
async def fetch(url):
    # Создаем асинхронную HTTP-сессию (контекстный менеджер автоматически закроет соединение)
    async with aiohttp.ClientSession() as session:
        # Выполняем GET-запрос по указанному URL (контекстный менеджер управляет соединением)
        async with session.get(url) as response:
            # Возвращаем текст ответа (await используется для асинхронного чтения)
            return await response.text()

# Основная асинхронная функция
async def main():
    # Вызываем fetch() для получения HTML-страницы (await ожидает завершения запроса)
    html = await fetch('https://example.com')
    # Выводим полученный HTML в консоль
    print(html)

# Запускаем асинхронное приложение
asyncio.run(main())
Виталий Уровень 33
14 июля 2025
В первом примере забыли про

print("Exit context")
Про выполнение кода понятней было бы так: 1. Вызов asyncio.run(main()): Запускается цикл событий asyncio Начинается выполнение функции main() 2. Вход в контекст (__aenter__):

async with AsyncContextManager():
Создаётся экземпляр AsyncContextManager Вызывается асинхронный метод __aenter__() Печатается "Enter context" Метод возвращает self (хотя в этом примере мы его не используем) 3. Выполнение блока кода внутри контекста:

print("Inside context")
Печатается "Inside context" 4. Выход из контекста (__aexit__): Автоматически вызывается асинхронный метод __aexit__()

print("Exit context")
Печатается "Exit context"
Slevin Уровень 64
14 июля 2025
Ладно...