Ein Async-Kontextmanager ist ein Objekt, das die asynchronen Methoden __aenter__ und __aexit__ definiert und in der Konstruktion async with verwendet wird. Ein solcher Manager ist erforderlich, um Ressourcen in asynchronen Funktionen korrekt zu öffnen/schließen: Verbindungen zu Datenbanken, Dateien, Sitzungen usw.
Beispiel der Implementierung:
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')
Der asynchrone Kontext ermöglicht es, den Event-Loop durch technische Verzögerungen nicht zu blockieren, was die Leistung von Concurrent-Programmen verbessert.
Kann man ein normales with innerhalb von async def verwenden?
Antwort: Ja, aber wenn die Operationen innerhalb des Kontextmanagers awaitable sind (await erfordern), wird genau async with benötigt. Das normale with unterstützt keinen asynchronen Enter/Exit und blockiert den Event-Loop oder schlägt fehl, wenn await innerhalb von enter/exit aufgerufen wird.
Beispiel:
async def foo(): with open('file.txt') as f: # das ist ok, da das Lesen synchron ist data = f.read() # Aber await kann innerhalb eines normalen Kontexts nicht verwendet werden, nur innerhalb von async with
Geschichte
Projekt: Webdienst mit asynchroner API.
Problem: Der Verbindungsmanager zur Datenbank verwendete ein normales with, aber es wurde await aufgerufen. Dies führte zu einem Fehler RuntimeError("Cannot use 'await' outside async function") und blockierte den Event-Loop in der Produktion.
Geschichte
Projekt: Chat über Websockets.
Problem: Bei der Arbeit mit Verbindungen wurden Websocket-Ressourcen nicht geschlossen (es wurde ein normaler synchroner Manager verwendet), was zu Speicherlecks und hängenden Verbindungen führte.
Geschichte
Projekt: Multithreaded asynchrone Aufgabenwarteschlange.
Problem: Der Aufgabenmanager implementierte
__aexit__nicht korrekt und vergaß, awaitable zurückzugeben. Dadurch wurde der Abschluss der Aufgaben nicht garantiert, und einige Aufgaben „hingen“ im System.