Qu'est-ce qui gouverne la "vitesse" d'un langage de programmation?
La "rapidité" d'un langage de programmation n'existe pas. Il n'y a que la vitesse d'un programme particulier écrit par un programmeur particulier exécuté par une version particulière d'une implémentation particulière d'un moteur d'exécution particulier s'exécutant dans un environnement particulier.
L'exécution du même code écrit dans le même langage sur le même ordinateur avec des implémentations différentes peut entraîner d'énormes différences de performances. Ou même en utilisant différentes versions de la même implémentation. Par exemple, si vous exécutez exactement le même benchmark ECMAScript sur la même machine avec une version de SpiderMonkey d'il y a 10 ans, une version de cette année entraînera probablement une augmentation des performances comprise entre 2 × –5 ×, voire même 10 ×. Cela signifie-t-il que ECMAScript est 2 × plus rapide que ECMAScript, car exécuter le même programme sur la même machine est 2 × plus rapide avec la nouvelle implémentation? Cela n'a pas de sens.
Cela at-il quelque chose à voir avec la gestion de la mémoire?
Pas vraiment.
Pourquoi cela arrive-t-il?
Ressources. Argent. Microsoft emploie probablement plus de personnes qui préparent du café pour leurs programmeurs de compilateur que l'ensemble de la communauté PHP, Ruby et Python réunies, qui emploie des personnes sur leurs ordinateurs virtuels.
Pour plus ou moins toute fonctionnalité d’un langage de programmation ayant un impact sur les performances, il existe également une solution. Par exemple, C (je l'utilise ici en tant que remplaçant d'une classe de langages similaires, dont certains existaient même avant le C) n'est pas sûr pour la mémoire, de sorte que plusieurs programmes en C exécutés en même temps peuvent piétiner la mémoire de l'autre. Donc, nous inventons la mémoire virtuelle et faisons en sorte que tous les programmes C passent par une couche d'indirection afin qu'ils puissent prétendre qu'ils sont les seuls fonctionnant sur la machine. Cependant, c'est lent et nous avons donc inventé la MMU et implémenté la mémoire virtuelle dans le matériel pour l'accélérer.
Mais! Les langues sans danger pour la mémoire n'ont pas besoin de tout ça! Avoir de la mémoire virtuelle ne les aide pas un bit. En réalité, c'est pire: non seulement la mémoire virtuelle n'aide pas les langages sécurisés, mais la mémoire virtuelle, même lorsqu'elle est mise en œuvre matériellement, a toujours un impact sur les performances. Cela peut être particulièrement préjudiciable aux performances des éboueurs (c’est ce qu’utilisent un grand nombre d’implémentations de langages sécurisés pour la mémoire).
Autre exemple: les processeurs grand public modernes utilisent des astuces sophistiquées pour réduire la fréquence d’absence de mémoire cache. Beaucoup de ces astuces consistent à essayer de prédire quel code sera exécuté et quelle mémoire sera nécessaire dans le futur. Cependant, pour les langues avec un degré élevé de polymorphisme d'exécution (par exemple, les langages OO), il est vraiment très difficile de prédire ces modèles d'accès.
Mais il existe un autre moyen: le coût total des échecs de mémoire cache correspond au nombre d’erreurs de cache multiplié par le coût d’un échec individuel. Les processeurs traditionnels tentent de réduire le nombre de manquements, mais que se passerait-il si vous pouviez réduire le coût d'un manquement individuel?
Le processeur Azul Vega-3 a été spécialement conçu pour exécuter des machines virtuelles virtualisées. Il disposait d'une MMU très puissante avec des instructions spécifiques pour aider à la récupération de place et à la détection des échappements (l'équivalent dynamique de l'analyse des échappements statiques), ainsi que de puissants contrôleurs de mémoire et l'ensemble du système. pourrait encore progresser avec plus de 20000 casses en suspens en vol. Malheureusement, comme la plupart des processeurs spécifiques à une langue, sa conception a tout simplement été dépassée et forcée par les «géants» Intel, AMD, IBM et autres.
L'architecture de la CPU n'est qu'un exemple qui a une incidence sur la facilité ou la difficulté d'obtenir une implémentation hautes performances d'un langage. Un langage comme C, C ++, D, Rust qui conviendra parfaitement au modèle de programmation CPU moderne, sera plus facile à créer rapidement qu’un langage qui doit "combattre" et contourner le CPU, comme Java, ECMAScript, Python, Ruby , PHP.
Vraiment, tout est une question d'argent. Si vous dépensez des sommes égales pour développer un algorithme hautes performances dans ECMAScript, une implémentation hautes performances d’ECMAScript, un système d’exploitation hautes performances conçu pour ECMAScript, une unité centrale hautes performances conçue pour ECMAScript comme précédemment des décennies pour faire en sorte que les langues de type C aillent vite, vous obtiendrez probablement des performances égales. À l'heure actuelle, beaucoup plus d'argent a été dépensé pour créer rapidement des langages de type C plutôt que pour des langages de type ECMAScript, et les suppositions de ces langages sont intégrées dans toute la pile, des MMU aux processeurs, en passant par les systèmes d'exploitation. systèmes de mémoire virtuelle jusqu'aux bibliothèques et les cadres.
Personnellement, je connais très bien Ruby (qui est généralement considéré comme un "langage lent"), je vais donc donner deux exemples: la Hash
classe (l'une des structures de données centrales dans Ruby, un dictionnaire clé-valeur) dans Rubinius L’implémentation de Ruby est écrite en Ruby pur à 100% et a à peu près les mêmes performances que leHash
classe dans YARV (l'implémentation la plus largement utilisée), écrite en C. Et il existe une bibliothèque de manipulation d'images écrite en tant qu'extension C pour YARV, qui possède également une "version de secours" (lente) de Ruby pure pour les implémentations ne supporte pas C qui utilise une tonne de trucs Ruby hautement dynamiques et réfléchissants; Une branche expérimentale de JRuby, utilisant le framework d’interpréteur Truffle AST et le framework de compilation Graal JIT d’Oracle Labs, peut exécuter cette "version de secours" pure Ruby aussi rapidement que YARV peut exécuter la version C hautement optimisée d’origine. Ceci est tout simplement (enfin, n'importe quoi) réalisé par des personnes très intelligentes qui effectuent des tâches très intelligentes avec des optimisations d’exécution dynamiques, une compilation JIT et une évaluation partielle.