Pourquoi parler d’asynchrone en Python ?
La programmation asynchrone répond à un problème très concret : un programme passe souvent plus de temps à attendre qu’à calculer. Il attend une réponse HTTP, une base de données, un fichier, une API ou un socket réseau. Pendant cette attente, un script classique reste bloqué. Avec l’asynchrone, Python peut suspendre une opération en attente et faire avancer une autre tâche.
Ce n’est pas une façon magique de rendre tout code plus rapide. C’est surtout utile pour les traitements I/O-bound : appels réseau, scraping, APIs, files de messages, websockets, bots, microservices ou traitements qui multiplient les petites attentes. Pour du calcul pur, il faudra plutôt regarder du côté du multiprocessing, de NumPy ou d’extensions natives.
Pour remettre ce sujet dans le parcours Python du site, vous pouvez aussi relire le langage Python, apprendre à coder en Python et les conseils pour écrire un code Python propre et lisible.
La boucle d’événements : le chef d’orchestre
Au centre du modèle se trouve l’event loop, ou boucle d’événements. Son rôle est simple : garder une liste de tâches, exécuter celles qui sont prêtes, suspendre celles qui attendent, puis revenir dessus quand leur attente est terminée. Une coroutine ne tourne donc pas en parallèle comme un thread système ; elle coopère avec les autres coroutines en rendant explicitement la main.
Cette coopération se fait avec await. Quand Python rencontre un await sur une opération asynchrone, il peut reprendre une autre tâche au lieu de rester immobile. C’est cette alternance qui donne l’impression de concurrence.
import asyncio
async def telecharger(n):
print(f"début {{n}}")
await asyncio.sleep(1)
print(f"fin {{n}}")
return n
async def main():
resultats = await asyncio.gather(
telecharger(1),
telecharger(2),
telecharger(3),
)
print(resultats)
asyncio.run(main())
Dans cet exemple, les trois attentes d’une seconde se superposent. Le programme ne dort pas trois secondes de suite : chaque coroutine suspend son exécution, puis la boucle reprend les autres.
Coroutine, tâche et future : trois mots à distinguer
Une fonction définie avec async def retourne une coroutine quand on l’appelle. Tant que cette coroutine n’est pas attendue ou planifiée, elle ne s’exécute pas. Une tâche, créée par exemple avec asyncio.create_task(), est une coroutine confiée à la boucle pour démarrer dès que possible. Une future représente un résultat disponible plus tard.
Dans la pratique, il faut surtout retenir ceci : await ma_coroutine() attend le résultat immédiatement dans le flux courant, tandis que asyncio.create_task(ma_coroutine()) lance une opération concurrente que l’on récupère ensuite.
Quand utiliser async/await ?
- Appeler beaucoup d’URLs ou d’APIs externes.
- Construire une API FastAPI qui attend souvent la base de données ou un service tiers.
- Gérer des websockets ou des notifications temps réel.
- Écrire des workers réseau efficaces sans multiplier les threads.
En revanche, inutile de transformer tout un projet en asynchrone si le code est majoritairement CPU-bound ou si les bibliothèques utilisées sont synchrones. Appeler une fonction bloquante dans une coroutine bloque quand même la boucle.
Le piège principal : mélanger async et blocage
Le code ci-dessous ressemble à de l’asynchrone, mais il bloque la boucle :
import time
async def mauvais_exemple():
time.sleep(2) # bloque toute la boucle
La bonne version utilise une primitive compatible avec la boucle :
import asyncio
async def bon_exemple():
await asyncio.sleep(2)
Le même raisonnement vaut pour les clients HTTP, les drivers SQL, les accès fichiers et les SDK externes. Une application asynchrone doit être asynchrone sur toute sa chaîne d’attente.
Conclusion
La programmation asynchrone en Python est un outil puissant quand le temps perdu vient des entrées/sorties. Son cœur tient en trois idées : une boucle d’événements, des coroutines suspendables et des points await où le programme accepte de laisser avancer autre chose. Une fois ces bases comprises, on peut passer à asyncio en pratique : tâches, timeouts, annulations et limitation de concurrence.
