ProgrammationDéveloppeur Python (asyncio/Backend)

Qu'est-ce qu'un gestionnaire de contexte Async (async context manager) en Python, comment le mettre en œuvre et où est-il indispensable ?

Réussissez les entretiens avec l'assistant IA Hintsage

Réponse.

Un gestionnaire de contexte Async est un objet qui définit des méthodes asynchrones __aenter__ et __aexit__ et est utilisé dans la construction async with. Ce gestionnaire est nécessaire pour ouvrir/fermer correctement des ressources dans des fonctions asynchrones : connexions à des bases de données, fichiers, sessions, etc.

Exemple de mise en œuvre :

class AsyncDBConnection: async def __aenter__(self): self.conn = await async_db_connect() return self.conn async def __aexit__(self, exc_type, exc, tb): await self.conn.close() async def main(): async with AsyncDBConnection() as conn: await conn.query('SELECT 1')

Le contexte asynchrone permet de ne pas bloquer la boucle d'événements avec des délais techniques, augmentant ainsi les performances des programmes concurrents.

Question piège.

Peut-on utiliser un simple with à l'intérieur d'un async def ?

Réponse : Oui, mais si les opérations à l'intérieur du gestionnaire de contexte utilisent awaitable (nécessitent await), il faut utiliser exactemnt async with. Le simple with ne prend pas en charge l'entrée/sortie asynchrone, il bloquera la boucle d'événements ou échouera si await est appelé à l'intérieur de enter/exit.

Exemple :

async def foo(): with open('file.txt') as f: # c'est ok, la lecture est synchrone data = f.read() # Mais il n'est pas possible d'attendre à l'intérieur d'un contexte normal, seulement à l'intérieur de async with

Exemples d'erreurs réelles dues à l'ignorance des subtilités du sujet.


Histoire

Projet : Service web avec API asynchrone.

Problème : Le gestionnaire de connexion à la base utilisait un simple with, mais un await a été appelé à l'intérieur. Cela a conduit à l'erreur RuntimeError("Cannot use 'await' outside async function") et à des blocages de la boucle d'événements en production.


Histoire

Projet : Chat sur Websockets.

Problème : Lors du travail avec des connexions, les ressources websocket n'étaient pas fermées (utilisation d'un gestionnaire synchrone), ce qui entraînait des fuites de mémoire et des connexions suspendues.


Histoire

Projet : File d'attente de tâches asynchrone multithread.

Problème : Le gestionnaire de tâches a mal implémenté __aexit__, oubliant de retourner un awaitable. En conséquence, l'achèvement des tâches n'était pas garanti, et une partie des tâches "suspendait" dans le système.