ProgrammazioneSviluppatore Python (asyncio/Backend)

Cosa sono i gestori di contesto Async (async context manager) in Python, come implementarli e dove sono indispensabili?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Il gestore di contesto Async è un oggetto che definisce i metodi asincroni __aenter__ e __aexit__ ed è utilizzato nella costruzione async with. Questo gestore è necessario per aprire/chiudere correttamente le risorse nelle funzioni asincrone: connessioni a database, file, sessioni, ecc.

Esempio di implementazione:

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')

Il contesto asincrono permette di non bloccare l'event loop con ritardi tecnici, aumentando le prestazioni dei programmi concorrenti.

Domanda trabocchetto.

È possibile utilizzare un normale with all'interno di async def?

Risposta: Sì, ma se le operazioni all'interno del gestore di contesto utilizzano awaitable (richiedono await), è necessario utilizzare proprio async with. Il normale with non supporta l'entrata/uscita asincrona e bloccherà l'event loop o genererà un errore se si chiama await all'interno di enter/exit.

Esempio:

async def foo(): with open('file.txt') as f: # va bene, la lettura è sincrona data = f.read() # Ma non puoi fare await all'interno di un contesto normale, solo all'interno di async with

Esempi di errori reali dovuti a mancanza di conoscenza dei dettagli del tema.


Storia

Progetto: Servizio web con API asincrona.

Problema: Il gestore della connessione al database utilizzava un normale with, ma all'interno veniva chiamato await. Questo ha portato all'errore RuntimeError("Cannot use 'await' outside async function") e blocchi dell'event loop in produzione.


Storia

Progetto: Chat su Websockets.

Problema: Durante il lavoro con le connessioni, le risorse websocket non venivano chiuse (utilizzavano un normale gestore sincrono), portando a perdite di memoria e connessioni bloccate.


Storia

Progetto: Coda di lavori asincrona multi-thread.

Problema: Il gestore delle attività ha implementato in modo errato __aexit__, dimenticando di restituire awaitable. A causa di ciò, il completamento delle attività avveniva in modo non garantito e alcune attività "sospese" nel sistema.