Python asyncio in pratica: misurazioni reali

Python e' il linguaggio piu' simile a PHP in termini di modello di esecuzione: interpretato, single-threaded (GIL), con una dominanza di framework sincroni. La transizione dal Python sincrono (Flask, Django + Gunicorn) all'asincrono (FastAPI, aiohttp, Starlette + Uvicorn) e' un'analogia precisa della transizione da PHP-FPM a un runtime basato su coroutine.

Di seguito una raccolta di casi di produzione, benchmark indipendenti e misurazioni.


1. Produzione: Duolingo — Migrazione a Python asincrono (+40% throughput)

Duolingo e' la piu' grande piattaforma di apprendimento linguistico (500M+ utenti). Il backend e' scritto in Python.

Nel 2025, il team ha iniziato una migrazione sistematica dei servizi dal Python sincrono all'asincrono.

MetricaRisultato
Throughput per istanza+40%
Risparmio costi AWS EC2~30% per servizio migrato

Gli autori notano che dopo aver costruito l'infrastruttura asincrona, la migrazione dei singoli servizi si e' rivelata "abbastanza semplice".

Fonte: How We Started Our Async Python Migration (Duolingo Blog, 2025)


2. Produzione: Super.com — Riduzione dei costi del 90%

Super.com (precedentemente Snaptravel) e' un servizio di ricerca hotel e sconti. Il loro motore di ricerca gestisce 1.000+ req/s, ingerisce 1 TB+ di dati al giorno ed elabora $1M+ in vendite giornaliere.

Caratteristica chiave del carico di lavoro: ogni richiesta effettua 40+ chiamate di rete verso API di terze parti. Questo e' un profilo puramente I/O-bound — un candidato ideale per le coroutine.

Il team ha migrato da Flask (sincrono, AWS Lambda) a Quart (ASGI, EC2).

MetricaFlask (Lambda)Quart (ASGI)Variazione
Costi infrastruttura~$1.000/giorno~$50/giorno−90%
Throughput~150 req/s300+ req/s2x
Errori nelle ore di puntaBaseline−95%−95%
LatenzaBaseline−50%2x piu' veloce

Risparmio di $950/giorno × 365 = ~$350.000/anno su un singolo servizio.

Fonte: How we optimized service performance using Quart ASGI and reduced costs by 90% (Super.com, Medium)


3. Produzione: Instagram — asyncio alla scala di 500M DAU

Instagram serve 500+ milioni di utenti attivi giornalieri su un backend Django.

Jimmy Lai (ingegnere di Instagram) ha descritto la migrazione ad asyncio in un talk al PyCon Taiwan 2018:

  • Sostituzione di requests con aiohttp per le chiamate HTTP
  • Migrazione dell'RPC interno ad asyncio
  • Ottenuto miglioramento delle prestazioni API e riduzione del tempo di inattivita' della CPU

Sfide: Elevato overhead CPU di asyncio alla scala di Instagram, la necessita' di rilevamento automatico delle chiamate bloccanti attraverso analisi statica del codice.

Fonte: The journey of asyncio adoption in Instagram (PyCon Taiwan 2018)


4. Produzione: Feature Store — Da thread a asyncio (−40% latenza)

Il servizio Feature Store ha migrato dal multithreading Python ad asyncio.

MetricaThreadAsyncioVariazione
LatenzaBaseline−40%−40%
Consumo RAM18 GB (centinaia di thread)Significativamente menoRiduzione sostanziale

La migrazione e' stata effettuata in tre fasi con suddivisione 50/50 del traffico di produzione per la validazione.

Fonte: How We Migrated from Python Multithreading to Asyncio (Medium)


5. Produzione: Talk Python — Da Flask a Quart (−81% latenza)

Talk Python e' uno dei piu' grandi podcast e piattaforme di apprendimento Python. L'autore (Michael Kennedy) ha riscritto il sito da Flask (sincrono) a Quart (Flask asincrono).

MetricaFlaskQuartVariazione
Tempo di risposta (es.)42 ms8 ms−81%
Bug dopo la migrazione2Minimi

L'autore nota: durante i test di carico, il massimo req/s differiva in modo insignificante perche' le query MongoDB richiedevano <1 ms. Il guadagno appare durante l'elaborazione di richieste concorrenti — quando piu' client accedono al server simultaneamente.

Fonte: Talk Python rewritten in Quart (async Flask)


6. Microsoft Azure Functions — uvloop come standard

Microsoft ha incluso uvloop — un event loop veloce basato su libuv — come predefinito per Azure Functions su Python 3.13+.

Testasyncio standarduvloopMiglioramento
10K richieste, 50 VU (locale)515 req/s565 req/s+10%
5 min, 100 VU (Azure)1.898 req/s1.961 req/s+3%
500 VU (locale)720 req/s772 req/s+7%

L'event loop standard a 500 VU ha mostrato ~2% di perdita di richieste. uvloop — zero errori.

Fonte: Faster Python on Azure Functions with uvloop (Microsoft, 2025)


7. Benchmark: task I/O-bound — asyncio 130x piu' veloce

Confronto diretto dei modelli di concorrenza su un task di download di 10.000 URL:

ModelloTempoThroughputErrori
Sincrono~1.800 s~11 KB/s
Thread (100)~85 s~238 KB/sBassi
Asyncio14 s1.435 KB/s0,06%

Asyncio: 130x piu' veloce del codice sincrono, 6x piu' veloce dei thread.

Per i task CPU-bound, asyncio non fornisce alcun vantaggio (tempo identico, +44% consumo di memoria).

Fonte: Python Concurrency Model Comparison (Medium, 2025)


8. Benchmark: uvloop — piu' veloce di Go e Node.js

uvloop e' un sostituto drop-in per l'event loop standard di asyncio, scritto in Cython su libuv (la stessa libreria alla base di Node.js).

Server TCP echo:

Implementazione1 KiB (req/s)100 KiB throughput
uvloop105.4592,3 GiB/s
Go103.264
asyncio standard41.420
Node.js44.055

Server HTTP (300 concorrenti):

Implementazione1 KiB (req/s)
uvloop + httptools37.866
Node.jsInferiore

uvloop: 2,5x piu' veloce dell'asyncio standard, 2x piu' veloce di Node.js, alla pari con Go.

Fonte: uvloop: Blazing fast Python networking (MagicStack)


9. Benchmark: aiohttp vs requests — 10x sulle richieste concorrenti

Libreriareq/s (concorrenti)Tipo
aiohttp241+Async
HTTPX (async)~160Async
Requests~24Sync

aiohttp: 10x piu' veloce di Requests per le richieste HTTP concorrenti.

Fonte: HTTPX vs Requests vs AIOHTTP (Oxylabs)


10. Contro-argomento: Cal Paterson — "Python asincrono non e' piu' veloce"

E' importante presentare anche i contro-argomenti. Cal Paterson ha condotto un benchmark approfondito con un database reale (PostgreSQL, selezione casuale di righe + JSON):

FrameworkTiporeq/sLatenza P99
Gunicorn + Meinheld/BottleSync5.78032 ms
Gunicorn + Meinheld/FalconSync5.58931 ms
Uvicorn + StarletteAsync4.95275 ms
SanicAsync4.68785 ms
AIOHTTPAsync4.50176 ms

Risultato: i framework sincroni con server C hanno mostrato throughput superiore e latenza di coda 2–3x migliore (P99).

Perche' l'asincrono ha perso?

Motivi:

  1. Una singola query SQL per richiesta HTTP — troppo poco I/O perche' la concorrenza delle coroutine abbia effetto.
  2. Il multitasking cooperativo con lavoro CPU tra le richieste crea una distribuzione "ingiusta" del tempo CPU — calcoli lunghi bloccano l'event loop per tutti.
  3. L'overhead di asyncio (event loop standard in Python) e' paragonabile al guadagno dall'I/O non bloccante quando l'I/O e' minimo.

Quando l'asincrono aiuta davvero

Il benchmark di Paterson testa lo scenario piu' semplice (1 query SQL). Come dimostrano i casi di produzione sopra, l'asincrono fornisce un guadagno drammatico quando:

  • Ci sono molte query DB / API esterne (Super.com: 40+ chiamate per richiesta)
  • La concorrenza e' elevata (migliaia di connessioni simultanee)
  • L'I/O domina sulla CPU (Duolingo, Appwrite)

Questo e' in linea con la teoria: piu' alto e' il coefficiente di blocco (T_io/T_cpu), maggiore e' il beneficio dalle coroutine. Con 1 query SQL × 2 ms, il coefficiente e' troppo basso.

Fonte: Async Python is not faster (Cal Paterson)


11. TechEmpower: framework Python

Risultati approssimativi da TechEmpower Round 22:

FrameworkTiporeq/s (JSON)
Uvicorn (raw)Async ASGIIl piu' alto tra Python
StarletteAsync ASGI~20.000–25.000
FastAPIAsync ASGI~15.000–22.000
Flask (Gunicorn)Sync WSGI~4.000–6.000
Django (Gunicorn)Sync WSGI~2.000–4.000

Framework asincroni: 3–5x piu' veloci di quelli sincroni nel test JSON.

Fonte: TechEmpower Framework Benchmarks


Riepilogo: cosa mostrano i dati Python

CasoSincrono → AsincronoCondizione
Duolingo (produzione)+40% throughput, −30% costiMicroservizi, I/O
Super.com (produzione)2x throughput, −90% costi40+ chiamate API per richiesta
Feature Store (produzione)−40% latenzaMigrazione da thread a asyncio
Talk Python (produzione)−81% latenzaFlask → Quart
I/O-bound (10K URL)130x piu' velocePuro I/O, concorrenza massiva
aiohttp vs requests10x piu' veloceRichieste HTTP concorrenti
uvloop vs standard2,5x piu' veloceTCP echo, HTTP
TechEmpower JSON3–5xFastAPI/Starlette vs Flask/Django
CRUD semplice (1 SQL)Sincrono e' piu' veloceCal Paterson: P99 2–3x peggiore per async
CPU-boundNessuna differenza+44% memoria, 0% guadagno

Conclusione chiave

Python asincrono fornisce il massimo beneficio con un alto coefficiente di blocco: quando il tempo di I/O supera significativamente il tempo CPU. Con 40+ chiamate di rete (Super.com) — 90% di risparmio sui costi. Con 1 query SQL (Cal Paterson) — l'asincrono e' piu' lento.

Questo conferma la formula di Efficienza dei task IO-bound: guadagno ≈ 1 + T_io/T_cpu. Quando T_io >> T_cpu — decine o centinaia di volte. Quando T_io ≈ T_cpu — minimo o zero.


Connessione con PHP e True Async

Python e PHP si trovano in una situazione simile:

CaratteristicaPythonPHP
InterpretatoSi'Si'
GIL / single-threadedGILSingle-threaded
Modello dominanteSync (Django, Flask)Sync (FPM)
Runtime asincronoasyncio + uvloopSwoole / True Async
Framework asincronoFastAPI, StarletteHyperf

I dati Python mostrano che la transizione alle coroutine in un linguaggio interpretato single-threaded funziona. L'entita' del guadagno e' determinata dal profilo del carico di lavoro, non dal linguaggio.


Riferimenti

Casi di produzione

Benchmark

Coroutine vs thread