Quelles caractéristiques sémantiques de Python (et d'autres langages dynamiques) contribuent à sa lenteur?
Aucun.
Les performances des implémentations de langage sont fonction de l'argent, des ressources et des thèses, et non des fonctionnalités de langage. Soi est beaucoup plus dynamique que Smalltalk et légèrement plus dynamique que Python, Ruby, ECMAScript ou Lua, et il avait une machine virtuelle qui surpassait toutes les machines virtuelles Lisp et Smalltalk existantes (en fait, la distribution Self livrée avec un petit interpréteur Smalltalk écrit en Self , et même cela était plus rapide que la plupart des machines virtuelles Smalltalk existantes), et était compétitif, et parfois même plus rapide que les implémentations C ++ de l'époque.
Ensuite, Sun a cessé de financer Self, et IBM, Microsoft, Intel et Co. ont commencé à financer C ++, et la tendance s'est inversée. Les développeurs Self ont quitté Sun pour créer leur propre entreprise, où ils ont utilisé la technologie développée pour Self VM pour construire l'une des machines virtuelles Smalltalk les plus rapides de tous les temps (la machine virtuelle animorphe), puis Sun a racheté cette entreprise et une version légèrement modifiée de que Smalltalk VM est désormais mieux connu sous le nom de "HotSpot JVM". Ironiquement, les programmeurs Java regardent les langages dynamiques comme «lents», alors qu'en fait, Javaétait lent jusqu'à ce qu'il adopte une technologie de langage dynamique. (Oui, c'est vrai: la machine virtuelle Java HotSpot est essentiellement une machine virtuelle Smalltalk. Le vérificateur de bytecode fait beaucoup de vérification de type, mais une fois que le bytecode est accepté par le vérificateur, la VM, et en particulier l'optimiseur et le JIT ne le font pas réellement beaucoup d'intérêt avec les types statiques!)
CPython ne fait tout simplement pas beaucoup de choses qui rendent les langages dynamiques (ou plutôt la répartition dynamique) rapides: compilation dynamique (JIT), optimisation dynamique, insertion spéculative, optimisation adaptative, désoptimisation dynamique, rétroaction / inférence de type dynamique. Il y a aussi le problème que presque tout le noyau et la bibliothèque standard sont écrits en C, ce qui signifie que même si vous accélérez Python 100x tout d'un coup, cela ne vous aidera pas beaucoup, car quelque chose comme 95% du code exécuté par un Le programme Python est C, pas Python. Si tout était écrit en Python, même des accélérations modérées créeraient un effet d'avalanche, où les algorithmes deviendraient plus rapides et les infrastructures de données de base deviendraient plus rapides, mais bien sûr, les structures de données de base sont également utilisées dans les algorithmes, et les algorithmes de base et les données de base les structures sont utilisées partout ailleurs,
Il y a deux ou trois choses qui sont notoirement mauvaises pour les langages OO gérés en mémoire (dynamiques ou non) dans les systèmes d'aujourd'hui. La mémoire virtuelle et la protection de la mémoire peuvent être un tueur pour les performances de récupération de place en particulier et les performances du système en général. Et cela est complètement inutile dans un langage à mémoire sûre: pourquoi se protéger contre les accès illégaux à la mémoire alors qu'il n'y a pas d'accès à la mémoire dans la langue pour commencer? Azul a découvert qu'il utilisait des MMU puissants et modernes (Intel Nehalem et plus récent, et l'équivalent d'AMD) pour aider à la collecte des ordures au lieu de le gêner, mais même s'il est pris en charge par le CPU, les sous-systèmes de mémoire actuels des systèmes d'exploitation traditionnels ne sont pas assez puissants pour permettre cela (c'est pourquoi la JVM d'Azul fonctionne réellement virtualisée sur nu plus l'OS, pas en son sein).
Dans le projet Singularity OS, Microsoft a mesuré un impact d'environ 30% sur les performances du système lors de l'utilisation de la protection MMU au lieu du système de type pour la séparation des processus.
Azul a également remarqué lors de la construction de leurs CPU Java spécialisés que les processeurs traditionnels traditionnels se concentrent sur la mauvaise chose en essayant de réduire le coût des échecs de cache: ils essaient de réduire le nombre d'erreurs de cache grâce à des choses telles que la prédiction de branche, la prélecture de la mémoire, etc. Mais, dans un programme OO fortement polymorphe, les modèles d'accès sont fondamentalement pseudo-aléatoires, il n'y a tout simplement rien à prévoir. Ainsi, tous ces transistors sont simplement gaspillés, et ce que l'on devrait faire à la place est de réduire le coût de chaque échec de cache individuel. (Le coût total est #miss * coût, le courant principal essaie de faire tomber le premier, Azul le second.) Les accélérateurs de calcul Java d'Azul pourraient avoir 20000 échecs de cache simultanés en vol et continuer à progresser.
Quand Azul a commencé, ils pensaient qu'ils prendraient quelques impromptu composants E / S et concevoir leur propre noyau CPU spécialisée, mais ce qu'ils ont réellement fini besoin de faire était exactement le contraire: ils ont pris un hors-the assez classique étagère à 3 adresses RISC et conçu leur propre contrôleur de mémoire, MMU et sous-système de cache.
tl; dr : La "lenteur" de Python n'est pas une propriété du langage mais a) sa mise en œuvre naïve (principale), et b) le fait que les CPU et OS modernes sont spécifiquement conçus pour faire tourner C rapidement, et les fonctionnalités qu'ils ont pour C n'aident pas (cache) ou même nuisent activement (mémoire virtuelle) aux performances Python.
Et vous pouvez insérer à peu près n'importe quel langage géré par la mémoire avec un polymorphisme ad hoc dynamique ici… en ce qui concerne les défis d'une implémentation efficace, même Python et Java sont à peu près «le même langage».