Python Async, pourquoi n’est-ce pas encore grand public ?
(tonybaloney.github.io)Python Async, pourquoi n’est-ce pas encore grand public ?
asyncio de Python est un outil puissant qui peut réduire les temps d’attente et améliorer de façon spectaculaire l’efficacité d’un programme dans les environnements riches en opérations d’I/O (entrées/sorties). Mais malgré ses nombreux avantages, tous les développeurs Python ne l’utilisent pas activement, et cela s’explique par plusieurs raisons fondamentales.
1. Ça complique tout dans la tête : la charge cognitive
Le principal obstacle, c’est la complexité. Le code synchrone est intuitif, car on peut suivre son flux d’exécution de haut en bas, dans l’ordre, comme lorsqu’on lit un livre.
Le code asynchrone, lui, fonctionne autrement. C’est un peu comme un cuisinier qui, pendant que les pâtes cuisent pour préparer un plat (temps d’attente), prépare la sauce d’un côté et, dans les moments restants, découpe les légumes. Au final, le repas peut être prêt plus vite, mais dans la tête du cuisinier, il faut sans cesse surveiller l’état de plusieurs tâches : « les pâtes sont-elles assez cuites ? », « la sauce ne brûle-t-elle pas ? », etc.
Comme le flux d’exécution du code passe ainsi d’un endroit à l’autre, il devient difficile de savoir quelle tâche est en cours et laquelle est en attente. Cela rend le débogage particulièrement délicat lorsqu’un bug survient et qu’il faut en retrouver la cause.
2. Un écosystème éclaté : la compatibilité des bibliothèques
Un autre problème de Python est que l’écosystème des bibliothèques est scindé entre « synchrone » et « asynchrone ». De nombreuses bibliothèques célèbres et pratiques (par exemple requests, la bibliothèque standard de fait pour les requêtes HTTP, ou beaucoup d’ORM) ne fonctionnent qu’en mode synchrone.
Si l’on utilise mal une bibliothèque synchrone dans du code asynchrone, le plus grand atout de l’asynchrone — la « boucle d’événements » — se retrouve complètement bloqué pendant l’exécution de ce code synchrone. C’est comme aménager plusieurs voies de circulation pour n’en utiliser qu’une seule : l’intérêt de l’asynchrone disparaît. Pour résoudre ce problème, il faut apprendre et adopter d’autres bibliothèques compatibles asynchrone (aiohttp, asyncpg, etc.), ce qui rend la courbe d’apprentissage encore plus raide.
3. Une seule cible à la fois : le GIL (verrou global de l’interpréteur)
Le GIL (Global Interpreter Lock) est l’une des caractéristiques historiques de Python : au sein d’un même processus, même s’il existe plusieurs threads, un seul thread peut s’exécuter à la fois. asyncio fonctionne sur un seul thread, il n’entre donc pas directement en conflit avec le GIL, mais l’existence du GIL limite malgré tout le champ d’application de async.
asyncio est optimisé pour exploiter les temps d’attente liés aux I/O (attente d’une réponse réseau, attente de lecture de fichier, etc.). Mais si une tâche gourmande en CPU avec des calculs très complexes est incluse dans une fonction async, toute la boucle d’événements s’arrête jusqu’à la fin de ce calcul. Pendant ce temps, les autres opérations d’I/O n’ont d’autre choix que d’attendre. En fin de compte, pour les tâches qui nécessitent un véritable traitement parallèle, il reste nécessaire d’utiliser d’autres techniques comme multiprocessing.
4. Un espoir pour l’avenir : Python 3.14 et la suppression du GIL
Mais il existe une nouvelle très encourageante face à ces limites. À partir de Python 3.13, une suppression optionnelle du GIL a été introduite à titre expérimental, et elle devrait gagner en maturité avec la version 3.14.
Porté par la proposition PEP 703, ce changement vise à permettre, si le développeur le souhaite, l’exécution de code Python sans GIL. Si cela devient réalité, Python pourra enfin tirer parti d’un véritable multithreading, avec plusieurs threads utilisant simultanément plusieurs cœurs CPU.
Combiné à asyncio, cela pourrait produire une synergie considérable. Les tâches d’I/O seraient traitées efficacement avec asyncio, tandis que les tâches CPU très intensives pourraient être déléguées à des threads séparés pour être exécutées en parallèle, sans les contraintes du GIL. Ce changement est considéré comme un tournant majeur pour l’écosystème Python et suscite de grands espoirs : il pourrait faire tomber nombre des barrières qui freinaient jusqu’ici l’adoption de la programmation async.
Aucun commentaire pour le moment.