ProgrammazioneSviluppatore Backend

Spiega come la programmazione asincrona è implementata in Python utilizzando async/await. Quali sono i vantaggi e le difficoltà di questo approccio?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

La programmazione asincrona è stata introdotta in Python a partire dalla versione 3.5 con l'introduzione delle parole chiave async e await. Inizialmente, per le attività asincrone venivano utilizzate librerie come asyncio e generatori basati su coroutine, che erano difficili da comprendere e mantenere. Con l'arrivo della sintassi async/await, il codice asincrono è diventato più esplicito e leggibile, avvicinandosi allo stile sincrono consueto.

Aspetto storico

Prima dell'introduzione di async/await, l'asincronicità era implementata tramite callback e generatori (ad esempio, utilizzando la libreria tornado o le vecchie API asyncio). Questo codice era difficile da debug e mantenere.

Problema

Il problema principale nella gestione di un gran numero di operazioni I/O simultanee (richieste di rete, input/output di file) nel codice sincrono è il blocco del thread principale. Questo porta a una diminuzione delle prestazioni e all'impossibilità di utilizzare efficientemente le risorse.

Soluzione

La programmazione asincrona utilizzando async/await consente di eseguire molte operazioni di input e output parallelamente all'interno di un singolo thread, evitando blocchi. Inoltre, la sintassi è simile alle comuni funzioni, il che facilita la leggibilità e il debug.

Esempio di codice:

import asyncio async def fetch_data(delay): print(f"Inizio del fetching dopo {delay}s di ritardo") await asyncio.sleep(delay) print(f"Fetch completato dopo {delay}s di ritardo") return delay async def main(): results = await asyncio.gather( fetch_data(1), fetch_data(2), fetch_data(3) ) print("Risultati:", results) asyncio.run(main())

Caratteristiche principali:

  • Nessun blocco del thread: le operazioni di input/output liberano il thread.
  • Sintassi esplicita (async/await) per le chiamate asincrone.
  • Facile integrazione con librerie che supportano asyncio.

Domande trabocchetto.

Una funzione definita con async def può essere chiamata come una funzione normale?

No. La chiamata a tale funzione restituisce un oggetto coroutine, che non viene eseguito fino a quando non viene passato all'event loop (ad esempio, utilizzando await o asyncio.run()).

def foo(): return 42 async def bar(): return 42 print(foo()) # 42 print(bar()) # <coroutine object bar at ...>

È possibile utilizzare await al di fuori di una funzione asincrona?

No. La parola chiave await deve essere utilizzata solo all'interno di funzioni dichiarate con async def. Tentare di utilizzare await al di fuori di tale funzione genererà un SyntaxError.

# Errore! await asyncio.sleep(1) # SyntaxError: 'await' outside async function

L'asincronicità funziona per operazioni non legate a I/O (ad esempio, computazioni)?

No. L'asincronicità è efficiente solo per operazioni di input/output. Per le attività computazionali è ancora necessario multiprocessing o threading, altrimenti l'event loop sarà bloccato.

Errori comuni e anti-pattern

Vantaggi:

  • Riduce significativamente i tempi di attesa per le operazioni di I/O.
  • Aumenta la reattività dei server e delle applicazioni.
  • Mantiene la natura single-thread del codice, evitando i problemi del multithreading.

Svantaggi:

  • Il codice asincrono è difficile da testare.
  • È necessario che le librerie supportino l'asincronicità (non tutte supportano asyncio).
  • È un'illusione credere che l'asincronicità acceleri i calcoli — questo è vero solo per I/O.

Esempio della vita reale

Caso negativo: Sviluppatori giovani hanno cercato di velocizzare l'applicazione usando async/await, ma hanno effettuato operazioni di calcolo in modo asincrono piuttosto che richieste di rete. L'applicazione non è accelerata. Vantaggi: si sono familiarizzati con la sintassi. Svantaggi: nessun profitto, codice complicato.

Caso positivo: Hanno gestito in modo asincrono migliaia di richieste API. Il server è riuscito a gestire più clienti senza aumentare le risorse. Vantaggi: notevole aumento delle prestazioni, architettura semplificata. Svantaggi: aumento della soglia di ingresso per i principianti.