Python async / await Explicat: Tutorialul 2026
Async în Python are reputația de a fi confuz. Nu trebuie să fie. Odată ce interiorizați o propoziție — async permite UNUI fir să ruleze mai multe sarcini legate de I/O intercalate — totul urmează.
Acest tutorial acoperă: ce fac de fapt async def și wait, când asincron câștigă vs când este instrumentul greșit, cele patru modele pe care le folosește fiecare bază de cod asincronă (secvențial, gather, semafor, timeout) și cele trei moduri în care începătorii înghit erorile.
Modelul mental cu o singură propoziție
Async în Python este concurență cooperativă într-un singur fir. Când codul dvs. atinge „așteaptă”, controlul revine la bucla de evenimente, care poate rula o altă sarcină în timp ce prima așteaptă I/O. Când I/O se termină, bucla reia prima sarcină de unde a fost întreruptă.
Asta este. Fără fire, procese, fără paralelism (în sensul CPython-cu-GIL). Doar un fir care jonglează cu multe sarcini care își petrec cea mai mare parte a timpului așteptând în rețea / disc / bază de date.
Asincronizarea este mai rapidă atunci când blocajul tău așteaptă, nu în calcul.
Programul asincron viabil minim cu trei linii
async def hello()— declară o coroutine. Apelarea luihello()nu rulează codul; creează un obiect corutine.wait asyncio.sleep(1)— redă controlul înapoi buclei de evenimente timp de 1 secundă.asyncio.run(hello())— creează o buclă de evenimente și rulează corotina până la finalizare.
Regula: `wait` numai în interiorul `async def`. Apelarea wait într-o funcție obișnuită este o SyntaxError.
Când asincron câștigă (și când nu)
Câștigări asincrone: lucru legat de I/O
Orice sarcină care își petrece cea mai mare parte a timpului de ceas de perete Așteptând este un candidat pentru asincron:
- Solicitări HTTP (API-uri externe, scraping, webhooks)
- Interogări baze de date
- Citiri / scrieri de fișiere
- Fluxuri WebSocket / gRPC
- Consumatori în coadă (Redis, RabbitMQ, Kafka)
Exemplu: preluarea a 100 de adrese URL.
Accelerare de 50-100x a ceasului de perete pentru lucrări grele I/O. Aici asincron își câștigă bugetul de complexitate.
Pierderi asincrone: lucru legat de CPU
Async nu vă oferă niciun paralelism pentru calcul. Deoarece este cooperant cu un singur thread, o buclă caldă CPU blochează întreaga buclă de evenimente.
Toate celelalte sarcini se înfometează în timp ce pbkdf2 rulează. Pentru lucru legat de CPU, accesați multiprocessing sau concurrent.futures.ProcessPoolExecutor, nu asincron.
Sarcina de lucru mixtă: run_in_executor
Dacă UNUL pas este greoi pentru CPU, iar restul este I/O, împachetați pasul CPU astfel încât să ruleze într-un pool de fire fără a bloca bucla:
„Niciunul” = grupul de fire implicite. Excelent pentru a apela biblioteci de sincronizare terță parte care sunt lente, dar nu puteți rescrie.
Cele patru modele
1. Secvenţial — o sarcină la un moment dat
Utilizați atunci când fiecare solicitare depinde de rezultatul celei anterioare.
2. asyncio.gather — trage deodată
Alegerea implicită pentru sarcini I/O independente. Dar: dacă adunați 10.000 de sarcini pe un singur API, veți primi descriptori de fișiere cu rate limitate sau de epuizare. Acolo intervine modelul semaforului.
3. Semafor — concurență maximă
asyncio.Semaphore(N) permite cel mult N sarcini să treacă de async with sem: în orice moment. Celelalte sarcini sunt în coadă. Utilizați pentru orice API extern cu o limită de rată sau o bază de date cu un pool de conexiuni.
4. Timeout — abandonați munca lentă
asyncio.wait_for anulează sarcina de bază după N secunde. Esențial pentru orice cod asincron care vorbește cu o rețea - nu faceți niciodată o așteptare nelimitată.
Cele trei capcane de înghițire a erorilor
Capcana 1: asyncio.gather cu return_exceptions=True
Este util când doriți să păstrați rezultate parțiale, dar LETAL dacă nu verificați fiecare rezultat:
Fără verificare, erorile dispar în tăcere.
Capcana 2: Aruncă și uită sarcini
Dacă background_work() se ridică, Python emite un avertisment la oprire și merge mai departe. Pentru orice vă interesează, stocați sarcina și „așteptați” sau utilizați „asyncio.TaskGroup” (3.11+) care propagă toate erorile.
Capcana 3: Codul de sincronizare în interiorul asincron
cererile este sincron. Chiar și în interiorul unui async def, requests.get blochează întreaga buclă până când sosește răspunsul. Utilizați httpx (sau aiohttp) pentru HTTP asincron.
Regulă: nu utilizați niciodată o bibliotecă I/O sincronă în codul asincron. Dacă biblioteca nu are o variantă asincronă, includeți-o în run_in_executor.
asyncio.TaskGroup — modul 2026 de a se extinde
Python 3.11 a adăugat „TaskGroup”, care rezolvă problema declanșării și uitării în mod curat:
Concurență structurată — fără erori pierdute, fără sarcini orfane. Preferați acest lucru față de create_task în codul modern.
Exemplu din lumea reală: scraper cu rată limitată
Toate cele patru modele în 15 linii: concurență delimitată (semafor), timeouts (wait_for), ramuri de eroare explicite (fără înghițire) și adunare pentru fan-out. Copiați și lipiți această formă în orice activitate I/O asincronă.
Async în Python are o curbă reală de învățare, dar modelul mental este simplu: un fir, pauze cooperative la wait, I/O se suprapune. Master gather + Semaphore + wait_for + TaskGroup și veți acoperi 95% din munca asincronă pe care o veți scrie vreodată.
Pasul următor: Pistă Python Senior are 20 de lecții practice despre asyncio, TaskGroup, aiohttp/httpx și modelele de concurență de mai sus - cu Python real rulând în browser.