- Python 3.14, publié cette fois-ci, affiche les meilleures performances de toutes les versions de CPython à ce jour
- En mono-thread, 3.14 montre une amélioration d’environ 27 % par rapport à 3.13, le gain du JIT reste minime, et l’interpréteur free-threading est légèrement plus lent en mono-thread
- En multi-thread, l’interpréteur FT profite de la suppression du GIL avec une accélération d’environ 3,1x sur Fibonacci et 2x sur le tri à bulles, ce qui le rend pertinent pour les charges CPU intensives en multi-thread
- En conclusion, 3.14 est le CPython le plus rapide, il est recommandé d’utiliser 3.11 ou une version ultérieure, PyPy reste très rapide et le JIT a encore besoin de gagner en maturité
Hypothèses et limites du benchmark
- Juste après la sortie officielle de Python 3.14, les résultats de benchmarks de performance comparant plusieurs versions de Python et d’autres langages ont été partagés
- Ce test repose sur de simples fonctions de récursion (Fibonacci) et d’itération (tri à bulles) écrites uniquement en Python pur
- En conditions réelles de développement, on mélange souvent du code natif en C/C++/Rust ; ces résultats ne se transposent donc pas à l’identique à des cas réels
Matrice de test
- Environnement de test
- 6 versions de Python (3.9 à 3.14), ainsi que PyPy, Node.js et Rust
- Interpréteurs Python : standard (Standard), JIT, free-threading (à partir de 3.13 pour chacun)
- Scripts de test : Fibonacci (
fibo.py), tri à bulles (bubble.py)
- Modes de threading : mono-thread, 4 threads
- Machines de test : Linux (Framework i5), macOS (M2)
- Les versions de Node.js et Rust sont également comparées à titre de référence
Scripts de test
- Fibonacci (
fibo.py) : structure récursive, exécution de fibo(40) dans chaque environnement
- Tri à bulles (
bubble.py) : tri de 10 000 nombres aléatoires
- Chaque test est répété 3 fois pour calculer une moyenne
- Le code de test est publié dans le dépôt GitHub
Benchmark #1 : Fibonacci (mono-thread)
- Python 3.14 enregistre une vitesse environ 27 % supérieure à 3.13 (6,59 s vs 8,26 s)
- À partir de la version 3.11, on passe de « très lent » à « un peu moins lent »
- PyPy est environ 5 fois plus rapide que 3.14, au niveau de Node.js, tandis que Rust est de loin le plus rapide
- Le free-threading reste plus lent que la version standard en mono-thread, mais l’écart se réduit avec 3.14 (environ 91 % des performances)
Interpréteurs JIT et free-threading
- Avec cette structure de fonction récursive, le JIT n’apporte aucun gain perceptible
- En mono-thread, le free-threading donne au contraire un résultat légèrement plus lent
- Les limites de gain du JIT peuvent varier selon la structure des fonctions
Benchmark #2 : tri à bulles (mono-thread)
- Python 3.14 est légèrement plus rapide que 3.11, mais l’écart est plus faible que sur Fibonacci (3.14 : 2,18 s, 3.11 : 2,48 s)
- PyPy est environ 18 fois plus rapide que 3.14
- Le JIT est parfois légèrement plus rapide sous Linux, tandis que sous macOS la différence est presque nulle
Benchmark #3 : Fibonacci (multi-thread)
- Avec l’interpréteur standard, le GIL (Global Interpreter Lock) empêche d’obtenir le gain attendu en augmentant le nombre de threads
- L’interpréteur free-threading (3.14) est 3,1 fois plus rapide que la version standard
- L’effet du JIT est presque inexistant
- Seuls les résultats de PyPy ont été mesurés ; Node.js/Rust ne sont pas comparés dans ce test
Benchmark #4 : tri à bulles (multi-thread)
- Le free-threading (3.14 FT) obtient un résultat 2 fois plus rapide que la version standard (3.14), avec un avantage particulièrement visible sur les tâches CPU intensives
- Le JIT ne montre pas d’avantage clair en performance
- Les performances du free-threading sur Mac sont remarquables
Conclusion
- CPython 3.14 affiche les meilleures performances de tous les CPython existants
- Si une mise à niveau est difficile, il est recommandé d’utiliser la version 3.11 ou ultérieure
- En pratique, l’interpréteur JIT n’a apporté qu’un gain de vitesse très limité
- L’interpréteur free-threading présente un avantage net dans les situations multi-thread à charge CPU intensive
- PyPy est de loin très rapide et mérite d’être exploré davantage
Divers
- Les résultats peuvent varier selon de nombreux paramètres d’environnement ; il est donc recommandé de faire ses propres benchmarks et vérifications
- Pour plus de détails et le code, voir le dépôt GitHub
1 commentaires
Avis sur Hacker News
J’aimerais parler de quelqu’un qui a changé ma vie. J’ai créé mon premier site web grâce au Flask Mega Tutorial, et juste avant le lancement, j’étais bloqué sur une partie critique de la gestion des fichiers corrompus dans Flask. J’ai posé une question, j’ai obtenu la solution via une réponse sur Stack Overflow, et je l’ai intégrée immédiatement au site. Ensuite, le site a énormément décollé. Je laisse le lien de la réponse à titre de référence : stackoverflow link
Ça n’a rien à voir avec Flask, mais je n’aime vraiment pas le nouveau logo de Flask. L’ancien avait un côté vintage, artisanal, alors que le nouveau ressemble à un truc qu’un lycéen aurait bricolé pour s’amuser avec WordArt. Ancien logo, Nouveau logo
Je voudrais demander si le site que tu as créé est yout.com. Je me demande si tu utilises toujours Flask
Ce serait vraiment génial qu’un jour, dans un nouvel élan de vibe coding, le site microphonetest.com revive
Je recommande d’éviter d’écrire des benchmarks en mesurant le temps à l’intérieur de la boucle puis en additionnant les mesures. Mieux vaut mesurer le temps d’exécution de la boucle entière puis diviser par le nombre d’itérations. Le jitter introduit par la mesure du temps elle-même peut fausser les résultats
timeitdans la bibliothèque standard : timeit docsJ’ai peur que Python se fige à la manière de TeX avec la version 3.14 lien Reddit
En voyant l’avis disant qu’il espérait justement que ça ne « s’arrête » pas, j’ai trouvé rafraîchissante l’idée que Donald Knuth accorde plus d’importance à un système qui produit durablement les mêmes résultats qu’au changement pour le changement. Dans un monde où tout devient obsolète au bout de quelques années, cette compulsion à devoir tout remplacer dès qu’un nouveau OOO apparaît ressemble à une maladie. Il n’y a aucune raison pour que nous ne puissions pas écrire du code destiné à durer 100 ans. Le code, au fond, c’est des mathématiques. On ne traite pas quelqu’un de ringard parce qu’il utilise des polynômes inventés il y a des millénaires ; de la même façon, il faut aussi savoir rester sur ce qui a fait ses preuves. Pas besoin d’être obsédé en permanence par les nouvelles versions et les nouveaux outils. Ceux qui écrivent du code qu’il n’y a aucune raison de changer sont, à mon avis, ceux qui apportent la vraie contribution
Un commentaire disant que la blague autour de πthon colle étonnamment bien à la situation
Chaque fois qu’il y a des nouvelles de Python, je trouve dommage qu’en 2025, PyPy suive toujours sa propre trajectoire. Je me demande si un jour Python sans GIL permettra aussi une C FFI sans GIL. Je pense que ce serait une énorme avancée pour Python
La C FFI pouvait déjà libérer le GIL manuellement depuis longtemps, donc je me demande ce que cela signifie exactement
Je pense qu’un écosystème sain, c’est comme pour le C : partir d’un langage et voir naître plusieurs dialectes à travers différentes implémentations de compilateurs. Cela favorise l’expérimentation et le progrès. Je considère aussi que les différences entre PyPy et CPython ne sont pas si grandes, et la compatibilité est élevée : guide de compatibilité pypy
C’est précisément le but du freethreading. D’après ce que je sais, plusieurs bibliothèques de C FFI n’ont pas encore été adaptées pour fonctionner sans GIL, ce qui empêche d’utiliser freethreading par défaut
Python a ajouté un JIT expérimental, ce qui le rapproche un peu plus de PyPy. Je ne sais pas s’ils construiront eux-mêmes un nouveau JIT ou s’ils finiront par fusionner avec PyPy, mais je suis convaincu qu’ils ont beaucoup appris de PyPy
J’aimerais demander si l’on pense vraiment que ce type de problème — fusionner des systèmes d’implémentation séparés — peut changer. Un scénario où Python introduirait par accident un autre breaking change nuisible aux performances serait préjudiciable à un large éventail d’utilisateurs. Je me demande si l’organisation Python souhaite réellement cela
Je trouve intéressant que PyPy soit plus rapide que CPython free threaded même sur du code multithread
Ce qui ressort, c’est à quel point la transition vers le non-GIL s’est faite en douceur. Comparé au passage de la version 2 à la 3, cette transition est vraiment remarquable. Le fait qu’on ait atteint rapidement une vitesse standard est très encourageant, et j’espère que les éléments incompatibles disparaîtront bientôt eux aussi
Si vous voulez faire rapidement un benchmark vous-même, je recommande le dépôt fast_langton_ant. Il suffit de l’exécuter comme ceci :
python3 server.py -s 10000000 -nJe me demande si la fonction de repli des commentaires (fold comment) dépend du karma ou d’autres options. J’ai trouvé marquant que l’anecdote sur l’aide de Miguel soit le message le plus populaire, mais c’est aussi la première fois que je me suis rendu compte qu’il n’y avait pas de fonction de repli quand on veut ne voir que les messages liés au sujet principal
Je pense qu’il est difficile d’évaluer l’usage réaliste de Python avec un benchmark qui n’utilise que des boucles simples et des opérations sur entiers. Les tables de hachage ou le traitement de chaînes sont plus proches du code réel. Beaucoup d’utilisateurs de Python confient les calculs numériques à des bibliothèques externes
Tous les benchmarks sont, par nature, conçus pour mesurer selon certains critères. Comme l’auteur a expliqué son objectif dans l’article, je recommande d’y jeter un œil si cela vous intéresse
J’aurais aimé un article plus approfondi, mais malgré tout, ce type de benchmark correspond mieux à mon usage réel. Dans mon cas, je fais le plus souvent des simulations de Monte-Carlo ou de petits calculs scientifiques répétés sur divers problèmes. Pour une simulation ponctuelle, je n’utilise pas forcément un algorithme rapide ou une bibliothèque que je maîtrise mal. Même si ça prend parfois 10 minutes, ce n’est pas grave (
scipyetnumpyrestent ceux que j’utilise le plus souvent). Comme je change souvent les hypothèses au fil des itérations, je privilégie une approche aussi simple que possible. La lisibilité et le code écrit sur le vif sont importants, et ce n’est pas grave si ce n’est pas très optimisé (par exemple : Fibonacci, tri à bulles, bouclesforimbriquées). Si j’ai vraiment besoin de performances, j’implémente directement le cœur encpp/zmp/pybind/numbaInclure des exemples courants comme des appels d’endpoint FastAPI ou des calculs
numpydans les benchmarks serait plus proche de l’usage réel de Python. Ces parties ne sont peut-être pas du pur code Python, mais en pratique, beaucoup de gens utilisent Python de cette façonJe me demande à quel point un benchmark basé uniquement sur une tight loop et des opérations sur des
intest réalisteJe me demande si le nouvel interpréteur expérimental en tail call (option
--with-tail-call-interp) a été inclus dans le benchmark : documentation officielle tail-call-interp. Comme il n’est pas mentionné dans les résultats du test, j’imagine que non. J’aimerais comparer l’écart entre l’interpréteur en tail call et les autres implémentations existantes--with-tail-call-interp). Je ne suis pas certain que les optimisations s’appliquent aussi aux appels récursifs en queue, mais si c’était le cas, on aurait dû voir un gain de performance dans le test Fibonacci