La programmation asynchrone est apparue dans le langage Python à partir de la version 3.5 avec l'introduction des mots-clés async et await. Initialement, des bibliothèques telles que asyncio et des générateurs basés sur des coroutines étaient utilisées pour des tâches asynchrones, ce qui était difficile à comprendre et à maintenir. Avec l'apparition de la syntaxe async/await, le code asynchrone est devenu plus explicite et lisible, se rapprochant du style synchrone habituel.
Avant l'apparition de async/await, l'asynchrone était réalisé à travers des callbacks et des générateurs (par exemple, en utilisant la bibliothèque tornado ou des API anciennes d'asyncio). Ce code était difficile à déboguer et à maintenir.
Le principal problème lors du traitement d'un grand nombre d'opérations I/O simultanées (requêtes réseau, entrée/sortie de fichiers) dans du code synchrone est le blocage du fil principal. Cela entraîne une baisse de performance et une incapacité à utiliser efficacement les ressources.
La programmation asynchrone à l'aide de async/await permet d'exécuter de nombreuses opérations d'entrée-sortie en parallèle dans un seul fil, évitant ainsi les blocages. De plus, la syntaxe est proche des fonctions normales, ce qui facilite la lisibilité et le débogage.
import asyncio async def fetch_data(delay): print(f"Début de la récupération après {delay}s de délai") await asyncio.sleep(delay) print(f"Récupération terminée après {delay}s de délai") return delay async def main(): results = await asyncio.gather( fetch_data(1), fetch_data(2), fetch_data(3) ) print("Résultats :", results) asyncio.run(main())
Une fonction définie avec async def peut-elle être appelée comme une fonction normale ?
Non. L'appel de cette fonction renvoie un objet coroutine qui n'est pas exécuté jusqu'à ce qu'il soit passé au boucle d'événements (par exemple, à l'aide de await ou asyncio.run()).
def foo(): return 42 async def bar(): return 42 print(foo()) # 42 print(bar()) # <coroutine object bar at ...>
Peut-on utiliser await en dehors d'une fonction asynchrone ?
Non. Le mot-clé await doit être utilisé uniquement à l'intérieur des fonctions déclarées avec async def. Tenter d'utiliser await en dehors de cette fonction déclenchera une SyntaxError.
# Erreur ! await asyncio.sleep(1) # SyntaxError: 'await' en dehors d'une fonction asynchrone
L'asynchrone fonctionne-t-il pour des opérations non liées à l'I/O (par exemple, des calculs) ?
Non. L'asynchrone est efficace uniquement pour les opérations d'entrée-sortie. Pour les tâches de calcul, le multiprocessing ou le threading sont toujours nécessaires, sinon la boucle d'événements sera bloquée.
Avantages :
Inconvénients :
Cas négatif : Des jeunes développeurs ont décidé d'accélérer l'application avec async/await, mais faisaient des calculs de manière asynchrone, et non des requêtes réseau. L'application ne s'est pas accélérée. Avantages : ils se sont familiarisés avec la syntaxe. Inconvénients : pas de profit, code devenu plus complexe.
Cas positif : Ils ont traité de manière asynchrone des milliers de requêtes à l'API. Le serveur a pu servir plus de clients sans augmenter les ressources. Avantages : la performance a considérablement augmenté, l'architecture est devenue plus simple. Inconvénients : la barre d'entrée pour les débutants a augmenté.