Ceci est un post invité de deronnax posté sous licence creative common 3.0 unported.
Bonjour, tous.
Vu qu’un des derniers posts de Sam&Max parlait de vitesse et des implémentations alternatives de Python, je propose un article sur l’état de ces différentes implémentations justement, et leur rapport à la vitesse.
Je commence par un petit rappel, pour nos lecteurs les moins aguerris avec l’écosystème Python : Python est un langage et aussi un interpréteur de référence, dont le vrai nom est CPython, écrit en C, qui livre également la bibliothèque standard Python (les modules datetime, urllib, collections, etc). CPython a des performances typiques de langage de script comme PHP ou Ruby, c’est à dire pas terribles, et a une conception assez simple, qui utilise des solutions simples pour répondre aux problèmes de langages de script. Celles qui font le plus parler d’elles (en mal évidement) étant la gestion de la mémoire par comptage de références (references counting), considérée moins performant qu’un vrai ramasse-miette (garbage collector) et assez limitée, et un verrou global de l’interpréteur, dont vous avez déjà dû entendre parler, le très mal-aimé GIL (Global Interpreter Lock), qui empêche entre autre à CPython d’avoir de vrai threads, c’est à dire des portions de code s’exécutant réellement en même temps, concurremment, sur des cœurs processeur différents. Néanmoins, rappelons-le encore : ces solutions permettent d’avoir un interpréteur simple et clair, pour lequel écrire des modules d’extensions en C est simple, ce qui est considéré actuellement comme le plus important. De plus, CPython lui-même n’ayant pas des performances significatives, du vrai multithread n’est pas un besoin pertinent. Si vous avez besoin de faire des traitements lourds, 9 fois sur 10 une bibliothèque spécialisée en C s’en occupe et fait elle même le traitement lourd en C dans ses threads, tel qu’OpenCV ou NumPy. En général vous avez très rarement besoin de vrai thread Python, et donc le GIL est relativement un faux problème.
La communauté Python s’est adaptée à cet absence de vrai concurrence, et différentes solutions sont apparues pour contourner le problème, je pense par exemple à l’excellent module multiprocessing, qui vous permet d’instancier différents interpréteurs et de les faire communiquer entre eux de manière transparente comme si c’était des threads.
D’une manière générale, quand il sera question d’un interpréteur alternatif, quatre points intéresseront la communauté :
- a-t-il de meilleures performances que CPython ?
- a-t-il un GIL/des vrais threads ?
- a-t-il un vrai ramasse-miette ?
- supporte-il les modules en C codés pour CPython ?
Je ne parlerai ici que des interpréteurs se voulant concurrents de CPython et remplissant la même niche. Les interpréteurs remplissant une tache un peu différente, et/ou nécessitant des modifications significatives de la manière d’écrire du code Python, ou n’ayant pas un niveau d’aboutissement significatif ne seront pas abordés, comme Cython ou Stackless Python. Voici une liste complète des implémentations de python.
Déjà, niveau implémentations alternatives, parlons des historiques Jython et IronPython ; ces deux projets sont des interpréteurs python tournant dans la VM existante d’un autre langage, respectivement la JVM Java d’Oracle (Sun, avant son rachat) et le CLR/.Net C# de Microsoft, apportant ainsi différents bénéfices, entre autre un vrai ramasse-miette et aussi des vrai threads qui carburent. Ils ont aussi en commun d’avoir été peu adoptés (très peu dans le cas d’IronPython) et qu’ils ne sont plus très vivants (très peu dans le cas d’IronPython, déjà lâché par Microsoft en 2010) : dernière release de Jython: mai 2015 ; IronPython: juin 2014. Ça fait mal. De plus, si à leur sortie ils donnaient par moment de meilleures performances que CPython, ce dernier s’est beaucoup amélioré et maintenant ils se valent au mieux. De plus, tous les deux sont très lourds, avec une empreinte mémoire beaucoup plus grosse et un temps de démarrage sans comparaison avec CPython. À déployer, c’est complètement la mort aussi, rien à voir avec apt-get install python/pypy. Très beaucoup la mort pour obtenir un IronPython qui tourne sous Mono sous Ubuntu. Ces projets sont bien partis pour disparaître s’ils ne changent pas. Et le support de python3 est inexistant pour tous les deux. Et vos modules codés en C, vous pouvez vous asseoir dessus.
Pour la petite histoire (anecdote à recaser en soirée pour briller), Jim Hugunin, le créateur de Jython, a commencé à écrire IronPython pour démontrer aux gens que la plateforme .Net était mauvaise et biens moins bonne que la JVM pour écrire une implémentation de langage. Jim a commencé à écrire une implémentation de Python en .Net, et à sa grande surprise a réussi à faire une implémentation très aboutie en peu de temps et a trouvé la plateforme .Net tellement géniale qu’il a quitté le projet Jython pour lancer IronPython.
Ensuite vient Pypy, l’interpréteur Python en python orienté vitesse. Pypy existe depuis une dizaine d’année et vise à être un drop-in remplacement de CPython, c’est à dire qu’ils suffit de l’installer et de changer les commandes “python truc” par “pypy truc” et hop ça marche. Ça fonctionne, à condition de ne pas utiliser de modules compilés en C. Si c’est néanmoins le cas, Pypy peut utiliser les modules en C de CPython moyennant recompilation, mais attention, les perfs sont moins bonne qu’avec CPython, dû au fait que l’API vient de CPython et impose à Pypy, un interfaçage/fonctionnement qui n’est pas le sien et ne supporte pas toute l’API. Pypy délivre actuellement des performances en moyenne neuf fois supérieures à CPython sur leur suite de tests, ce qui est assez bluffant. Après, à chacun de considérer si la suite de test de Pypy est représentative d’une utilisation réelle, ce qui est le problème existentielle de chaque implémentation Python alternative qui vous met sous le nez un graphe montrant qu’elle est X fois plus rapide que CPython sur sa suite de tests. Pypy utilise également un GIL, donc ne fourni pas de vrais threads, mais a dans un coin un projet de passer à un modèle de concurrence qui permettrait de s’affranchir du GIL, et dispose par contre d’un vrai ramasse-miette. Le support de Python 3 est minimum, en juin 2014 est sorti Pypy 2.4 supportant python version 3.2, l’équipe informant qu’il est néanmoins plus lent que Pypy visant python 2.7, autant vous dire qu’on est pas en avance.
Vous avez pu tomber sur des noms genre Unladden Swallow et Stackless Python : Unladen Swallow était un Pypy-like antérieur par des ingénieurs de Google qui voulait générer du JIT avec LLVM en promettant des performances 5 fois supérieurs à CPython. Le projet a échoué à tenir ses promesses et a fini par mourir doucement lors que Google a retiré son financement. Ce qui a pu être sauvé a été intégré dans Pypy (des améliorations au module Pickle). Stackless est un interpréteur modifié qui intègre les coroutines de base et d’autres trucs parallèles/asynchrone, il n’est pas un drop-in remplacement et demande d’écrire du python qui ne tournera que sur et pour lui.
Ensuite est venu il y a un an le “Pypy” de Dropbox, Pyston. Tout le monde a tapé sur Dropbox pour avoir réinventé sa roue carrée avec Pyston au lieu de contribuer à Pypy, Dropbox a répondu qu’ils utilisent une approche différente de celle de Pypy, ils utilisent un method-at-a-time JIT au lieu d’un tracing JIT, méthode qui a donné de si bons résultats avec le moteur javascript de Google, V8, en s’appuyant sur la célèbre LLVM, la “machine virtuelle pour le bas-niveau”. LLVM étant par ailleurs soutenue par des grands noms comme Apple et Intel, si Dropbox ne merde pas, ça pourrait donner un truc intéressant. De plus, contrairement à Pypy qui a choisi de peu supportter l’API C de CPython pour les modules, Pyston vise une compatibilité absolue avec l’API C, c’est une de ses priorité fondamentale . Nous pouvons en déduire que Dropbox a beaucoup de modules d’extension en C auxquels ils tiennent beaucoup. Pypy utilise un ramasse miette et un GIL. Un point fait néanmoins tousser avec Pyston, c’est que les créateurs déclarent ne vouloir que viser Python 2.7 et ne pas envisager de supporter python3. On a du mal à croire que Guido van Rossum travaille pour cette boite. Toutes ces informations viennent de la FAQ de Pyston. Le blog de Pyston, intéressant, explique leurs choix technique et rend compte de leur avancée : http://blog.pyston.org/.
Pyston a fait plusieurs chose intelligemment, notamment au lieu de réécrire un interpréteur, ils ont forké CPython et branché leurs systèmes de JIT dedans, ce qui leur a permis de sortir en moins d’un an une release de Pyston plutôt viable qui fait tourner beaucoup de choses et passe beaucoup de tests. Leur interpréteur est déjà 25% plus rapide que CPython sur leur suite de test, face à un Pypy 50% plus performant. C’est un petit tour de force.
Un énorme écueil d’écrire un interpréteur alternatif à CPython étaient les modules en C de la bibliothèque standard ; une partie significative des modules de la bibliothèque standard étaient écrits en C, donc si vous faisiez un interpréteur alternatif, il fallait aussi vous recoder dans le langage de votre interpréteur tous les modules de la bibliothèque standard que vous ne pouviez utiliser, ce qui implique de faire 10.000 tests pour s’assurer qu’ils ont exactement le même comportement que ceux de la bibliothèque standard, ce qui est extrêmement fastidieux et pénible. Depuis Python 3.3 en septembre 2012 , CPython fourni un recode en Python de tous ses module en C qui passent exactement la même suite de test et qui sont donc “garantis” (modulo erreur humaine, c’est une vaste et dure tâche) de se comporter exactement comme leurs congénères en C. C’est une énorme charge de travail en moins pour les développeurs d’interpréteurs alternatifs. Également, depuis Python 3.1 , l’import de modules, qui auparavant était une machinerie interne un peu obscure de l’interpréteur CPython, et donc qu’il fallait recoder en croisant les doigts pour que ça reproduise exactement le comportement de CPython sous peine de tout voir exploser, a été recodé en Python et est livré avec CPython, donc fini de redevoir recoder un système d’import, vous pouvez juste le reprendre et l’utiliser, ouf.
De tous, Pypy est le seul qui s’approche actuellement vaguement d’un “concurrent” sérieux à CPython, talonné par Pyston pour un futur proche. Et encore, ce n’est pas encore le drop-in remplacement parfait. Et tous ont un support de Python3 inexistant, sauf Pypy qui en a un insuffisant :). Et tous, en tant que VM complète (donc lourde) ou interpréteur-optimiseur visant à optimiser le code (et donc analyser), ont des temps de démarrage et d’atteinte de l’efficacité sans commune mesure avec CPython. Ils ne sont intéressants qu’en cas de long-running (genre, vos sites Django). Et tous utilisent un ramasse-miette, ce qui donne un comportement différents sur les objets “finalisés”. Alors que CPython a un comportement déterministe et détruit immédiatement les objets qui ne sont plus utilisés, les ramasse-miettes reportent leur destruction à un moment où il sera plus opportun de les détruire, potentiellement très longtemps ou jamais au pire des cas. C’est pour ça que par hygiène, il faut toujours libérer explicitement les ressources des objets représentants des ressources tel que les files-like objets représentants fichiers ou socket en utilisant leur méthode “close()” ou le manager “with” même si ça fonctionne très bien sans sous CPython. Pour les objets représentant des ressources limitées comme les fichiers, les sockets ou n’importe quel lien vers une ressource limitée procurée par l’OS, ne pas le faire signifie se prendre rapidement un stop de l’OS. D’une manière générale, CPython applique des solutions simples et déterministes qui offrent pas mal de garanties sympathiques (gestion des ressources, atomicité, alignement mémoire, adresse des objets en mémoire fixe, etc) qui sont maintenant considérées comme acquise et immuables par beaucoup de programmes python, malheureusement gênantes pour faire un interpréteur optimisant vraiment agressivement (là j’ai pas de sources mais c’est une complainte qui revient régulièrement dans les discussions des autres interpréteurs, surtout Pypy).
Parmi les news relatives à la vitesse de Python que l’article de S&M ne mentionne pas, la nouvelle release de la JVM vient avec un meilleur découplage des éléments la composant, et du coup il devient facile de l’utiliser pour un autre langage. IBM a fait un proof-of-concept en faisant un interpréteur python, qu’ils vont open-sourcer (et faire pareil avec Ruby). Pas d’altruisme là-dedans, c’est pour montrer au monde que leur VM est bien fichue. Ça pourrait être le nouveau Jython : http://www.infoworld.com/article/3014128/open-source-tools/ibms-open-source-jvm-project-could-also-speed-ruby-python.html.
Aussi, Microsoft s’étant visiblement, dernièrement, un peu amouraché de Python, on peut s’attendre que leur coopération à Python aille un peu plus loin. Ou pas.
Après, la triste vérité est que les langages dynamiques sont très durs à optimiser, parce qu’ils sont justement dynamiques, surtout Python où tout est modifiable, et donc interpréteurs/VMs ne peuvent être sûrs de rien et ne peuvent pas supprimer pleins de tests/résolutions/recherches, et que Python, malgré toutes ses implémentations pleines de bonne volonté, ne sera jamais aussi rapide que le C, ni même que Java. La dernière fois que j’ai regardé (~3 ans), le benchmark game donnait python 20x plus lent que le C, contre 2x pour le Java. Ça fait réfléchir. Tous les efforts poussés à fond, on tapera peut être le 5x plus lent que le C :)
Actuellement, un core-contributeur de CPython (français, cocorico !) travaille sur différents sujets visant à améliorer significativement les performances de CPython. C’est la première fois qu’un chantier aussi vaste est lancé visant à sérieusement améliorer les performances de CPython. Le site sur le sujet : http://faster-cpython.readthedocs.org/
Ces différents projets acceptent les dons. Je vous encourage évidemment vivement à donner. La vitesse de Python est l’un dernier écueil qui pourraient faire choisir à un décideur technique pressé un autre langage plutôt que Python. Des meilleurs interpréteurs Python, c’est plus de tâches accomplies en Python, donc plus de postes pour les développeurs Python, donc plus de demande, et donc de meilleurs salaires. Quand vous donnez à des projets Python, vous vous versez de l’argent à vous-même dans le futur. De plus, ça aide à faire reculer les parts de marché de cette horreur qu’est PHP et de la concurrence de Ruby et Go, et ça, c’est toujours ça de pris :)
Même une petite somme est significative. Avec l’euro fort, vous avez un grand pouvoir. Et un grand pouvoir implique de grandes responsabilités.
Donner à Cpython : https://www.python.org/psf/donations/
Donner à Pypy : http://pypy.org/
Voila, vous savez tout sur l’histoire des différents interpréteurs Python. Avec ça, vous pourrez vous la pétez en soirée et niquer des tonnes de meufs. Ou pas.
Merci beaucoup !
Pour voir (l’immense) travail à réaliser pour porter Pypy vers Python 3 : http://pypy.org/py3donate.html
La JVM d’oracle ou Sun mais pas d’IBM
Oula oui
gg
Il y a également nuitka, pythran, numba et py14 qui permettent de compiler du Python (standard, sans avoir à le modifier).
J’ai l’impression qu’il y a parfois une confusion dans l’article, entre JVM (Java Virtual Machine) et VM (Virtual Machine générique, qui peut être pour tout et n’importe quoi y compris le python.
Sinon c’est très instructif, mais relativement imbitable à lire. Ça mériterait d’être rephrasé avec des paragraphes plus court, quelques gros titres, des phrases un peu mieux tournées, etc.
J’essayerais de le faire si j’ai le temps, mais je garantis rien.
Je suis d’accord pour la lisibilité, je ne l’ai pas travaillé, c’est plus un dump de pensées.
Par contre pour la confusion VM/JVM, je veux bien que tu me pointes un point à confusion.
Y a t il un moyen rapide de verifier la présence d’un module codé en C parmi la liste importée.
Ca peut être fastidieux de chercher toutes les doc à chaque fois.
Bonjour,
apt-get install jython
Au revoir.
Cet article semble manquer une ouverture récente.
Microsoft a mis à disposition un projet pour choisir le JIT
Un des buts affichés étant “Add a C API to CPython for plugging in a JIT”
Cela diminuerait à terme les efforts pour avoir/maintenir des interpréteurs alternatifs.
Le projet https://github.com/Microsoft/Pyjion
Non, cette ouverture récente à été couverte justement très récemment par cet article de S&M:http://sametmax.com/evolution-de-python/. C’est à lui que je fais référence dans l’intro et au passage ou je dit que Microsoft s’est amouraché de Python.
Mais le temps à passé et la filiation temporelle est devenue moins évidente. Je vais éditer l’article pour le’ parler plus explicitement.
Ah non c’est bon.
Je viens de relire les passages où tu mentionnes la JVM. Et effectivement y’a pas de confusion. Désolé j’étais un peu dans le pâté.
“Jim a commencé à écrire une implémentation de Python en .Net”
C’est pas plutôt avec la JVM ?
Ça c’est typiquement un article pour se donner bonne conscience quand on sent que son langage favori est menacé à terme car il n’arrive plus à évoluer dans le sens de l’Histoire. Mais je comprends, j’étais encore comme cela il y a 2 ans. Mais ça c’était avant que je me mette à d’autres langages…
Menacé ? Par quoi ? JS (Si oui, no comment quoi) ? Perso, Python n’est pas mon langage préféré. Mais, il reste sympathique par bien des aspects. Après, comme j’ai envie de le dire depuis un très long moment sur Sam&Max, y’a pas que le Web dans l’informatique… Et, souvent Python est présent, désolé de te l’apprendre. (Et pourtant, Dieu sait que ca me coute “d’encenser” Python qui n’a pas besoin de ca pour faire son trou)
@ParadoxEd
Tout doucement, je n’ai pas abandonné Python, je suis formateur officiel dans un centre de recherche si tu veux tout savoir même.
Je disais ça dans le sens où c’est quand même un aveu d’échec sur les perfs et sur le packaging…la lib async ne sauvera pas le monde…c’est nouveau en Python mais ça a 30 ans comme techno l’async…l’avenir c’est le CSP (https://en.wikipedia.org/wiki/Communicating_sequential_processes). L’asynchrone est mis en place par les langages dynamiques pour pallier leurs lacunes en terme de perf…c’est loin d’être l’avenir.
Moi non plus, je ne développe pas pour le web, enfin plus maintenant, vu comment ça me saoule et que le web “grand public” est devenu tout pourri (je suis un vieux) ;)
“De plus, ça aide à faire reculer les parts de marché de cette horreur qu’est PHP et de la concurrence de Ruby et Go, et ça, c’est toujours ça de pris :)”
… ça me fait un peu ticker ceci : si ça marchait comme ça alors la réussite de python ne se ferait pas sur le mérite technique.
De plus si je prends les langages sus-cités : Ruby et PHP souffrent des même défauts que python sur les performance : en gros ça a pas été pensé pour ça. Et c’est d’ailleurs tout l’article : python n’as jamais était pensé pour être performant et essayer de faire des JVM/interpréteur alternatif est un travail énorme qui se heurte toujours à des problèmes que l’on peut résumer par “python n’as pas été fait pour ça (à la base)”.
Mais pour Go, le langage est utilisable partout ou python est utilisable et est beaucoup plus performant comparé à python. Go n’est pas tellement plus complexe que python (dispose d’un GC performant pour que le programmeur n’est pas trop à se soucier de la gestion mémoire), gère la concurrence de manière beaucoup plus simple/intelligente/novatrice que l’asynchrone (CSP) et a l’avantage d’être typé statiquement (ho oui c’est un avantage !).
Donc bon, moi j’ai envie de dire “problem solved : use Go”.
Je sais que je suis sur un blog pro-python ce post est une mi-provocation et j’espère bien que vous allez tous m’expliquez que j’ai tords, car oui j’ai tords : quand les perf c’est pas le plus important utilisez ce que vous aimez; puis si vraiment les perf sont le plus important Go fait des sacrifices sur point comparé à d’autre langage.
Mais bon quand même, vu l’utilisation possible des 2 langages j’avais besoin de le dire, et sur un blog pro-Go ça aurait été trop facile :p
Pour moi, il ne s’agit pas de savoir si CPython est plus ou moins rapide que les autres langages ou implémentations, mais de savoir si cette rapidité est suffisante pour les applications qu’on veut développer. Ceci en considérant, bien sûr, la facilité et la rapidité de développement, et pas seulement la rapidité d’exécution. Autrement dit, si un temps de réponse de 0.1s est suffisant, le fait de changer pour un langage plus complexe afin d’arriver à une réponse en 0.01s est une perte de temps.
Actuellement, je développe surtout des logiciels graphiques avec PyQt (PyQt5 maintenant), et je dois dire que j’en suis pleinement satisfait. Mon plus gros programme graphique fait le traitement d’un concours international et dépasse 30000 lignes de code. J’intègre beaucoup de choses dans ces programmes, et comme ça a été dit, le code Python passe très rapidement la main à des parties codées en C ou en C++, et ça marche donc très bien. De plus, je les transforme souvent en exécutable “standalone” avec cx_freeze. Ainsi, sous Windows, avec un installeur comme innosetup, un utilisateur peut installer et utiliser ces logiciels sans savoir que c’est écrit en Python!
Si une petite partie de type mathématiques est un peu critique en rapidité d’exécution, il est facile de la traiter avec Cython pour la compiler en C ou en C++. En utilisant la méthode (peu connue) avec décorateurs pour déclarer le type des variables, le code Python n’a quasiment pas à être modifié. On peut aussi, bien sûr, compiler des modules entiers écrits en C ou en C++: CPython a la méthode dans sa doc, et pour l’avoir déjà utilisée, je confirme que ça marche!
Périodiquement, je regarde si une nouvelle implémentation ou un autre langage, me ferait gagner quelque chose dans mes développements, et jusqu’à présent, je n’ai rien trouvé de convaincant: il y a toujours quelque chose qui ne va pas: manque de bibliothèques, pas de développement récent, syntaxe dépassée (ex: Python2), pas assez mûr pour la production, etc… Mais comme je ne suis pas marié avec CPython, ça ne m’empêche pas de continuer à chercher, d’où ma présence sur cet excellent site!
Le 25 mai, Pyston a livré la version 5.0 avec un changement radical : ils sont passé du système de ramasse-miette à celui de comptage de référence, pour mieux coller à l’API de CPython, parce que c’était trop compliqué de conserver la même API C que CPython en utilisant une gestion de mémoire différente (Pypy se bat avec ce problème depuis sa création, comme expliqué dans l’article). J’éditerai l’article sous peu.
Cool !
Une mise à jour très en retard:
le 31 janvier 2017, Dropbox a arrêté Pyston, parce que les gars de Pyston n’avaient pas atteint l’amélioration de performance visée dans les temps, la tache s’est révélée plus difficile que prévue (ça alors, exactement comme les gars de Unladen Swallow, incroyable), et le 9 août 2016, Mozilla a donné 200.000$ à Pypy pour améliorer le support de Python 3, dont le support de Python3 est devenu très acceptable.
On peut voir qu’il y a une malédiction des implémentations alternatives de Python, toutes les tentatives échouent.