Guida Asyncio Python
Guida Asyncio Python
Per neolaureati in informatica e sviluppatori alle prime armi con Python
Indice dei contenuti Guida Asyncio Python
- Cos’è asyncio e quando nasce
- La programmazione concorrente: il fondamento di asyncio
- Le caratteristiche principali
- Come funziona asyncio: event loop, coroutine e task
- Esempi pratici di codice
- Best practice: quando usare asyncio (e quando no)
- Conclusioni e formazione continua
1. Cos’è asyncio e quando nasce
asyncio è una libreria della Standard Library di Python progettata per scrivere codice concorrente utilizzando la sintassi async/await. Non si tratta di un framework esterno, ma di un modulo integrato direttamente nel linguaggio, il che ne garantisce stabilità, manutenzione ufficiale e piena compatibilità con l’ecosistema Python.
La libreria fu introdotta in modo sperimentale con Python 3.4 (PEP 3156, marzo 2014) e stabilizzata progressivamente nelle versioni successive. Con Python 3.5 arrivarono le parole chiave async e await (PEP 492), che semplificarono enormemente la sintassi rispetto alle coroutine basate sui generator. Oggi, con Python 3.10 e versioni successive, asyncio è considerata matura, stabile e parte integrante dello stack di sviluppo moderno in Python.
La nascita di asyncio risponde a una necessità concreta del mondo dello sviluppo software: gestire in modo efficiente operazioni di I/O (letture di file, richieste HTTP, query a database) senza bloccare l’esecuzione del programma in attesa di una risposta. In un’epoca in cui le applicazioni devono servire migliaia di richieste simultanee, il modello sincrono tradizionale mostra i suoi limiti strutturali.
2. La programmazione concorrente: il fondamento di asyncio
Prima di addentrarci nei meccanismi di asyncio, è fondamentale comprendere il concetto di programmazione concorrente. Si tratta di un paradigma in cui più operazioni sono in corso nello stesso intervallo di tempo, anche se non necessariamente in esecuzione simultanea sul processore.
È importante distinguere tre concetti spesso confusi:
- Concorrenza: più attività vengono gestite nello stesso arco temporale, alternandosi nell’uso delle risorse. È il modello di asyncio.
- Parallelismo: più attività vengono eseguite fisicamente nello stesso istante su core o CPU distinti. È il modello del modulo multiprocessing.
- Multithreading: più thread condividono la stessa memoria e si alternano nell’esecuzione, ma in Python il Global Interpreter Lock (GIL) limita il vero parallelismo CPU-bound.
asyncio abbraccia la concorrenza cooperativa: le coroutine cedono esplicitamente il controllo all’event loop quando sono in attesa di un’operazione lenta (ad esempio una risposta di rete), permettendo ad altre coroutine di proseguire nel frattempo. Nessun thread aggiuntivo, nessun overhead di sincronizzazione complessa: tutto gira su un singolo thread, governato dall’event loop.
3. Le caratteristiche principali – Guida Asyncio Python
asyncio offre un insieme ricco di funzionalità, organizzate su due livelli secondo la documentazione ufficiale Python:
API di alto livello (per sviluppatori applicativi)
- Esecuzione concorrente di coroutine con pieno controllo sul ciclo di vita.
- I/O di rete e comunicazione tra processi (IPC).
- Controllo di sottoprocessi (subprocess).
- Distribuzione di task tramite code (queue).
- Sincronizzazione del codice concorrente (lock, semafori, eventi).
API di basso livello (per sviluppatori di framework e librerie)
- Creazione e gestione dell’event loop.
- Implementazione di protocolli efficienti tramite transport.
- Bridge tra librerie basate su callback e la sintassi async/await.
Una caratteristica distintiva di asyncio è essere la fondazione su cui poggiano numerosi framework Python ad alte prestazioni: FastAPI, aiohttp, Starlette, Tortoise ORM e molti altri. Comprendere asyncio significa quindi avere una base solida per l’intero ecosistema asincrono di Python.
4. Come funziona asyncio: event loop, coroutine e task
L’Event Loop
L’event loop è il cuore di asyncio. Si tratta di un ciclo che gestisce una coda di operazioni da eseguire: preleva un job, lo avvia, lo mette in pausa quando entra in attesa, e nel frattempo esegue altri job. La documentazione ufficiale lo descrive efficacemente come un ‘direttore d’orchestra’: coordina tutte le coroutine, decide chi ha il controllo in ogni istante, e riprende le operazioni sospese appena la risorsa attesa è disponibile.
Le Coroutine
Una coroutine è una funzione definita con async def. A differenza di una funzione ordinaria, la sua chiamata non esegue immediatamente il corpo: restituisce invece un oggetto coroutine che deve essere esplicitamente avviato dall’event loop. La parola chiave await, usata all’interno di una coroutine, segnala un punto di sospensione: l’event loop può in quel momento passare il controllo ad un’altra coroutine in attesa di esecuzione.
I Task
Un Task è una coroutine ‘avvolta’ e associata all’event loop tramite asyncio.create_task(). Creando un task, si pianifica l’esecuzione della coroutine: essa viene aggiunta alla coda dell’event loop e verrà eseguita non appena il controllo le sarà ceduto. asyncio.run() è il punto di ingresso raccomandato per avviare l’event loop e il programma principale.
5. Esempi pratici di codice
5.1 Hello World asincrono
Il classico esempio dalla documentazione ufficiale: una coroutine main() che stampa un messaggio, attende un secondo senza bloccare il thread, e poi stampa un secondo messaggio.
import asyncio
async def main():
print('Hello ...')
await asyncio.sleep(1) # non blocca il thread
print('... World!')
asyncio.run(main())
5.2 Esecuzione concorrente di più task
Immaginiamo di dover effettuare tre chiamate API separate. Con asyncio.gather() possiamo avviarle tutte in parallelo e attendere il completamento di tutte:
import asyncio
async def fetch_data(nome, secondi):
print(f'Avvio richiesta: {nome}')
await asyncio.sleep(secondi) # simula attesa di rete
print(f'Completata: {nome}')
return f'Dati da {nome}'
async def main():
risultati = await asyncio.gather(
fetch_data('API-Utenti', 2),
fetch_data('API-Ordini', 1),
fetch_data('API-Prodotti', 3),
)
print(risultati)
asyncio.run(main())
# Tempo totale: ~3 secondi (non 6!)
Il guadagno è immediato: tre operazioni che sincroniamente richiederebbero 6 secondi vengono completate in 3, grazie alla concorrenza cooperativa.
6. Best practice: quando usare asyncio (e quando no)
Usare asyncio quando…
- L’applicazione è I/O-bound: attende risposte di rete, letture/scritture su disco, query a database. Asyncio eccelle in questi scenari.
- Si deve gestire un alto numero di connessioni simultanee (server web, API gateway, bot, WebSocket).
- Si lavora con framework che già la supportano nativamente: FastAPI, aiohttp, Starlette, asyncpg.
- Si sviluppano microservizi che comunicano tra loro tramite rete.
Evitare asyncio quando…
- Il codice è CPU-bound: calcoli matematici intensivi, elaborazione di immagini, machine learning. In questi casi conviene il modulo multiprocessing o librerie come concurrent.futures con ProcessPoolExecutor.
- Il team non ha familiarità con il paradigma asincrono: il debugging di codice async può essere complesso e introdurre errori sottili.
- Il progetto usa librerie sincrone che non supportano async: mescolare codice sincrono e asincrono richiede attenzione e l’uso di run_in_executor() per non bloccare l’event loop.
- La semplicità è prioritaria: per script semplici o task singoli, il codice sincrono è più leggibile e più facile da mantenere.
Regola d’oro: usare asyncio quando si attende qualcosa di esterno al programma. Non usarlo quando si calcola qualcosa internamente.
7. Conclusioni e formazione continua
asyncio rappresenta uno degli strumenti più potenti e moderni del panorama Python. Comprenderne i fondamenti (event loop, coroutine, task, programmazione concorrente) significa fare un salto qualitativo importante nel proprio percorso come sviluppatore: non solo si scrive codice più efficiente, ma si acquisisce un modello mentale fondamentale per affrontare le sfide delle applicazioni distribuite, dei servizi cloud-native e delle architetture a microservizi.
L’evoluzione del software è però sempre più rapida. Nuove versioni di Python, nuovi framework, nuovi paradigmi architetturali emergono con cadenza serrata. Per un team IT aziendale, restare al passo non è più una scelta opzionale: è una condizione necessaria per rimanere competitivi sul mercato. La formazione continua è l’unico strumento reale per colmare questo divario tra la velocità dell’innovazione e le competenze interne.
In questo scenario, Innovaformazione propone soluzioni formative concrete e flessibili per le aziende. Il Corso Python,, è pensato per sviluppatori che vogliono costruire basi solide o approfondire aspetti avanzati del linguaggio. Per le realtà che necessitano di competenze specifiche, Innovaformazione può attivare su richiesta corsi dedicati a framework particolari, come proprio asyncio, con contenuti calibrati sulle esigenze del team.
La formazione si svolge in modalità online, in classe virtuale, con calendario concordato in base alle disponibilità aziendali. È inoltre possibile accedere alla formazione finanziata attraverso il piano formativo Fondimpresa, riducendo significativamente i costi per le imprese aderenti.
Richiedi un preventivo o maggiori informazioni:
- Email: info@innovaformazione.net
- Tel: 3471012275 — Dario Carrassi
Investire nella formazione del proprio team oggi significa non inseguire il cambiamento domani: significa guidarlo.
Per altri articoli tecnici consigliamo di navigare sul nostro blog QUI.
Articoli correlati
Claude Code e Migrazioni SAP
Claude Code controllo remoto
Opportunità Carriera Contabilità SAP
Guida SIA AI
Guida Dual LLM Verification
