15. Programmation Asynchrone
async/await,asyncio, coroutines, tasks,gather(),timeouts,aiohttp.
15.1 Coroutines
Fonction définie avec async def qui retourne un objet coroutine :
async def dire_bonjour():
print("Bonjour")
await asyncio.sleep(1) # cède le contrôle
print("Au revoir")15.2 Exécuter une coroutine
import asyncio
async def main():
print("Début")
await dire_bonjour()
print("Fin")
asyncio.run(main())asyncio.run() crée la boucle d’événements, exécute main(), et nettoie.
15.3 await
Suspend la coroutine courante jusqu’à ce que l’awaitable soit terminé.
async def fetch_data():
await asyncio.sleep(2)
return {"data": 42}
async def main():
resultat = await fetch_data()
print(resultat)15.4 Tâches concurrentes
async def main():
# Créer des tâches (elles s'exécutent en concurrence)
t1 = asyncio.create_task(fetch_data())
t2 = asyncio.create_task(fetch_data())
# Attendre les deux
r1, r2 = await asyncio.gather(t1, t2)
print(r1, r2)asyncio.gather() — lance toutes les tâches en concurrence :
results = await asyncio.gather(
fetch_data(1),
fetch_data(2),
fetch_data(3),
)15.5 Timeout
async def main():
try:
resultat = await asyncio.wait_for(
fetch_data(),
timeout=1.0 # lève asyncio.TimeoutError après 1s
)
except asyncio.TimeoutError:
print("Trop long !")15.6 asyncio.sleep()
Remplacement non-bloquant de time.sleep() :
await asyncio.sleep(0.1) # 100 ms sans bloquer le thread15.7 Boucle d’événements avancée
async def main():
loop = asyncio.get_running_loop()
# call_soon, run_in_executor (pour bloquant)
resultat = await loop.run_in_executor(
None, # thread pool par défaut
bloquant_function, arg1, arg2
)15.8 Exemple : téléchargements concurrents
import asyncio
import aiohttp
async def télécharger(url: str) -> str:
async with aiohttp.ClientSession() as session:
async with session.get(url) as response:
return await response.text()
async def main():
urls = [
"https://example.com",
"https://python.org",
"https://docs.python.org",
]
pages = await asyncio.gather(*[télécharger(u) for u in urls])
for url, contenu in zip(urls, pages):
print(f"{url}: {len(contenu)} caractères")15.9 async for et async with
# Itération asynchrone
async for chunk in stream():
traiter(chunk)
# Gestionnaire de contexte asynchrone
async with aiohttp.ClientSession() as session:
...15.10 Structures de données asynchrones
from asyncio import Queue, Semaphore
queue = asyncio.Queue()
await queue.put(item)
item = await queue.get()15.11 Bonnes pratiques
- Ne pas mélanger I/O bloquant et
async(utiliserrun_in_executor). - Éviter
asyncio.run()dans une boucle déjà en cours. - Utiliser
asyncio.gather()pour la concurrence, pas des boucles séquentielles. - Toujours gérer les timeouts pour les I/O réseau.