Gestionnaires de contexte asynchrones en Python avec asyncio

Les gestionnaires de contexte asynchrones sont un mécanisme de Python permettant de gérer des ressources de manière asynchrone, garantissant leur libération même en cas d'exception, via la syntaxe async with.

Fonctionnement des gestionnaires de contexte

Un gestionnaire de contexte standard est un objet Python implémentant les méthodes __enter__() et __exit__(). Il s'utilise généralement avec l'instruction with pour assurer une acquisition et une libération systématique des ressources.

# Utilisation synchrone classique
with open("donnees.txt", "r") as fichier:
    contenu = fichier.read()
# Le fichier est automatiquement fermé ici

Gestionnaires de contexte asynchrones

Introduits par la PEP 492, les gestionnaires de contexte asynchrones définissennt des versions asynchrones de ces méthodes, nommées __aenter__() et __aexit__(). Ces méthodes sont des coroutines et doivent donc être définies avec async def. Ils ne peuvent être utilisés qu'au sein de programmes asyncio, typiquement dans des coroutines, grâce à l'instruction async with.

# Utilisation asynchrone
async with GestionnaireAsynchrone() as gestionnaire:
    # Traitement asynchrone avec la ressource
    await traitement_asynchrone()

Implémentation d'un gestionnaire de contexte asynchrone

Pour créer un gestionnaire de contexte asynchrone, on définit une classe avec les deux méthodes asynchrones requises. Ces méthodes peuvent contenir des opérations d'attente (await) comme l'accès à un réseau ou des entrées/sorties.

import asyncio

class GestionnaireConnexionAsync:
    async def __aenter__(self):
        print('Établissement de la connexion...')
        # Simulation d'une opération asynchrone longue
        await asyncio.sleep(1)
        self.connexion = "Établie"
        return self

    async def __aexit__(self, exc_type, exc_val, exc_tb):
        print('Fermeture de la connexion...')
        await asyncio.sleep(0.5)
        self.connexion = None
        # Retourne False pour ne pas supprimer les exceptions
        return False

Exemple d'utilisation complète

L'instruction async with automatise l'appel aux méthodes d'entrée et de sortie du gestionnaire. Le code suivant démontre une utilisation typique où la ressource (simulée) est acquise et libérée de manière contrôlée.

async def operation_principale():
    print("Début de la tâche principale.")
    async with GestionnaireConnexionAsync() as connexion:
        statut = connexion.connexion
        print(f"Connexion active: {statut}")
        # Simulation d'un travail avec la ressource
        await asyncio.sleep(1)
    print("Tâche terminée, connexion libérée.")

# Point d'entrée du programme asyncio
asyncio.run(operation_principale())

L'exécution produit la séquence d'attente et de messages suivante, illustrant la suspension et la reprise du flux d'exécution :

Début de la tâche principale.
Établissement de la connexion...
Connexion active: Établie
Fermeture de la connexion...
Tâche terminée, connexion libérée.

Ce modèle assure que la logique de nettoyage définie dans __aexit__() s'exécute de manière fiable, que le bloc async with se termine normalement ou suite à une exception.

Étiquettes: Python asyncio coroutine async with context manager

Publié le 9 juin à 22h24