Supposons qu’un programme soit écrit en deux langues distinctes, qu’il s’agisse de la langue X et de la langue Y, si leurs compilateurs génèrent le même code octet, pourquoi devrais-je utiliser la langue X au lieu de la langue Y? Qu'est-ce qui définit qu'une langue est plus rapide qu'une autre?
Je vous pose cette question car vous voyez souvent des gens dire des choses telles que: "C est la langue la plus rapide, ATS est une langue rapide comme C". Je cherchais à comprendre la définition de "rapide" pour les langages de programmation.
programming-languages
compilers
Rodrigo Valente
la source
la source
Réponses:
Plusieurs raisons peuvent être envisagées pour choisir un langage X plutôt qu'un langage Y. La lisibilité du programme, la facilité de programmation, la portabilité sur de nombreuses plates-formes, l'existence de bons environnements de programmation peuvent être de telles raisons. Cependant, je n’examinerai que la rapidité d’exécution demandée dans la question. La question ne semble pas prendre en compte, par exemple, la vitesse de développement.
Deux langues peuvent être compilées sous le même code octet, mais cela ne signifie pas que le même code sera produit.
En fait, le bytecode est uniquement du code pour une machine virtuelle spécifique. Il présente des avantages techniques, mais n'introduit pas de différences fondamentales avec la compilation directe pour un harware spécifique. Donc, vous pourriez aussi bien envisager de comparer deux langages compilés pour une exécution directe sur le même ordinateur.
Cela dit, la question de la vitesse relative des langues est ancienne et remonte aux premiers compilateurs.
Pendant de nombreuses années, à cette époque, Professional considérait que le code écrit à la main était plus rapide que le code compilé. En d'autres termes, le langage machine était considéré comme plus rapide que les langages de haut niveau tels que Cobol ou Fortran. Et c'était à la fois plus rapide et généralement plus petit. Les langages de haut niveau sont encore développés car ils étaient beaucoup plus faciles à utiliser pour de nombreuses personnes qui n'étaient pas des informaticiens. Le coût d'utilisation de langages de haut niveau porte même un nom: le taux d'expansion, qui peut concerner la taille du code généré (un problème très important à cette époque) ou le nombre d'instructions réellement exécutées. Le concept était principalement expérimental, mais le ratio était supérieur à 1 au début, car les compilateurs effectuaient un travail assez simple selon les normes actuelles.
Ainsi, le langage machine était plus rapide que Fortran.
Bien sûr, cela a changé au fil des ans, à mesure que les compilateurs sont devenus plus sophistiqués, au point que la programmation en langage assembleur est maintenant très rare. Pour la plupart des applications, les programmes en langage assembleur sont en concurrence médiocre avec le code généré par l'optimisation des compilateurs.
Cela montre que l'un des problèmes majeurs est la qualité des compilateurs disponibles pour le langage considéré, leur capacité à analyser le code source et à l'optimiser en conséquence.
Cette capacité peut dépendre, dans une certaine mesure, des caractéristiques du langage pour souligner les propriétés structurelles et mathématiques de la source afin de faciliter le travail du compilateur. Par exemple, un langage pourrait permettre l'inclusion d'énoncés concernant les propriétés algébriques des fonctions définies par l'utilisateur, de manière à permettre au compilateur d'utiliser ces propriétés à des fins d'optimisation.
Le processus de compilation peut être plus facile, produisant ainsi un meilleur code, lorsque le paradigme de programmation du langage est plus proche des fonctionnalités des machines qui interprèteront le code, qu’il soit réel ou virtuel.
Un autre point est de savoir si les paradigmes mis en œuvre dans le langage sont fermés au type de problème programmé. Il faut s’attendre à ce qu’un langage de programmation spécialisé dans des paradigmes de programmation spécifiques compile très efficacement les fonctionnalités liées à ce paradigme. Par conséquent, le choix d'un langage de programmation peut dépendre, pour des raisons de clarté et de rapidité, du choix d'un langage de programmation adapté au type de problème à programmer.
La popularité du C pour la programmation système est probablement due au fait que ce dernier est proche de l’architecture de la machine et que la programmation système est également directement liée à cette architecture.
Un autre problème sera plus facilement programmé, avec une exécution plus rapide utilisant la programmation logique et les langages de résolution de contraintes .
Les systèmes réactifs complexes peuvent être programmés de manière très efficace avec des langages de programmation synchrones spécialisés comme Esterel, qui incorpore des connaissances très spécialisées sur de tels systèmes et génère un code très rapide.
Pour prendre un exemple extrême, certains langages sont hautement spécialisés, tels que les langages de description de syntaxe utilisés pour programmer des analyseurs. Un générateur d'analyseur n'est qu'un compilateur pour de tels langages. Bien sûr, il n’est pas encore complet, mais ces compilateurs sont extrêmement bons pour leur spécialité: produire des programmes d’analyse syntaxique efficaces. Le domaine de la connaissance étant restreint, les techniques d'optimisation peuvent être très spécialisées et réglées très finement. Ces générateurs d’analyseurs sont généralement bien meilleurs que ce qui pourrait être obtenu en écrivant du code dans une autre langue. Il existe de nombreux langages hautement spécialisés avec des compilateurs qui produisent un code excellent et rapide pour une classe restreinte de problèmes.
Par conséquent, lors de l'écriture d'un grand système, il peut être judicieux de ne pas compter sur une seule langue, mais de choisir la meilleure langue pour différents composants du système. Ceci pose bien entendu des problèmes de compatibilité.
Un autre point qui compte souvent est simplement l’existence de bibliothèques efficaces pour les sujets programmés.
Enfin, la vitesse n'est pas le seul critère et peut être en conflit avec d'autres critères tels que la sécurité du code (par exemple en ce qui concerne les mauvaises entrées, ou la résilience face aux erreurs système), l'utilisation de la mémoire, la facilité de programmation (bien que la compatibilité des paradigmes puisse réellement aider cela). ), taille du code objet, maintenabilité du programme, etc.
La vitesse n'est pas toujours le paramètre le plus important. En outre, cela peut prendre différentes formes, telles que la complexité, qui peut être une complexité moyenne ou une complexité pire. En outre, dans un grand système comme dans un programme plus petit, il existe des domaines dans lesquels la rapidité est essentielle, et d'autres dans lesquels cela importe peu. Et ce n’est pas toujours facile de déterminer cela à l’avance.
la source
Bien que tout soit finalement exécuté sur le processeur * , il existe diverses différences entre les différentes langues. Voici quelques exemples.
Langages interprétés Certains langages sont interprétés plutôt que compilés , par exemple Python, Ruby et Matlab. Cela signifie que le code Python et Ruby ne se compile pas en code machine, mais est plutôt interprété à la volée. Il est possible de compiler Python et Ruby sur une machine virtuelle (voir point suivant). Voir aussi cette question . L'interprétation est généralement plus lente que le code compilé pour diverses raisons. L'interprétation elle-même peut non seulement être lente, mais il est également plus difficile de faire des optimisations. Cependant, si votre code passe le plus clair de votre temps sur les fonctions de bibliothèque (cas de Matlab), les performances n'en pâtiront pas.
Machine virtuelle Certains langages sont compilés en bytecode , un "code machine" inventé qui est ensuite interprété. Les exemples par excellence sont Java et C #. Bien que le bytecode puisse être converti en code machine à la volée, le code fonctionnera probablement encore plus lentement. Dans le cas de Java, une machine virtuelle est utilisée pour la portabilité. Dans le cas de C #, il peut y avoir d'autres problèmes tels que la sécurité.
Frais généraux Certaines langues négocient efficacité et sécurité. Par exemple, certaines versions de Pascal vérifieraient que vous n’accédez pas à un tableau en dehors des limites. Le code C # est "géré", et cela a un coût. Le garbage collection est un autre exemple courant. Il permet au programmeur de gagner du temps, mais n'est pas aussi efficace que la gestion de la mémoire. Il existe d'autres sources de charge, telles que l'infrastructure pour la gestion des exceptions ou la prise en charge de la programmation orientée objet.
* En fait, les systèmes hautes performances de nos jours exécutent également le code sur les GPU et même sur les FPGA.
la source
Il y a différents facteurs pour choisir X au lieu de Y, comme
Certains langages conviennent au développement de projets d’entreprise tels que C # ou Python, mais d’autre part, d’autres sont utiles pour la programmation système telle que C ++.
Vous devez déterminer sur quelle plate-forme vous allez travailler et quelle application vous allez créer.
la source
Le langage de programmation "le plus rapide" que vous pouvez obtenir avec n'importe quelle plate-forme est le langage d'assemblage du chipset auquel vous faites face. A ce niveau, il n'y a pas de traduction. Cependant, il est nécessaire de savoir comment le chipset exécute les instructions, en particulier celles capables de fonctionner en parallèle.
La conversion de C en assemblage est très "superficielle": elle est proche de un à un mais elle est plus lisible. Cependant, il a beaucoup de couches au-dessus en raison des bibliothèques standard pour améliorer la portabilité. Le compilateur aurait besoin de moins de choses pour obtenir le code assembleur et les optimisations les plus puissantes permettent généralement d’apporter des modifications spécifiques à la machine.
C ++ ajoute un langage plus riche. Cependant, étant donné que le langage ajoute tellement de complexité, il devient plus difficile au compilateur de créer un code optimal pour la plate-forme.
Ensuite, nous passons de l’autre côté de l’échelle. Langues interprétées Celles-ci tendent à être les plus lentes car outre le travail, il faut un peu de temps pour analyser le code et le convertir en appels machine.
Ensuite, nous avons ceux entre les deux. Généralement, ils ont une couche de machine virtuelle optimisée pour la plate-forme. Et le compilateur va créer du code pour que la machine virtuelle s'exécute. Parfois, cela se produit tout à la fois comme Perl, Pascal, Ruby ou Python. Ou en plusieurs étapes comme java.
Certaines de ces machines virtuelles ajoutent la notion de compilateur JIT qui accélère également l'exécution en créant un code au niveau de la machine plutôt qu'en traduisant le code d'octet intermédiaire.
Certaines machines virtuelles sont de bas niveau, ce qui permet moins de traduction du code octet en code machine. Ce qui accélère les choses tout en gardant la portabilité.
la source
*p++=*q++;
sur de nombreuses machines a été plus rapide quearray1[i]=array2[i];
sur de nombreux processeurs, l'inverse est souvent vrai, de sorte que les compilateurs peuvent finir par convertir le style précédent en code - ce n'est guère une conversion "superficielle".-O0
il ne fera aucune optimisation. Les optimisations sont un bonus que vous obtenez avec le compilateur, mais le langage en lui-même peut se traduire de manière quasi directe en assembleur.Un point qui n’a pas encore été mentionné est que dans certaines langues, exécuter le même morceau de code plusieurs fois exécutera toujours la même séquence d’actions; il suffit donc à l’ordinateur de déterminer une fois ce que la section de code doit faire. L'un des principaux avantages du dialecte JavaScript "strict" consiste en ce qu'une fois que le moteur JavaScript détermine le fonctionnement d'un morceau de code, il peut utiliser ces informations lors de sa prochaine exécution. sans "utiliser strict", il ne peut pas.
Par exemple, en l'absence de "use strict", un morceau de code comme:
peut renvoyer une variable X dans le contexte d’appel immédiat, s’il en existe une, ou une variable X à partir d’un contexte d’appel externe, ou peut renvoyer
Undefined
. Pire, en boucle comme:le moteur JavaScript n'a aucun moyen de savoir ce qui
g()
pourrait faire aveci
[ou pourg
lui-même d'ailleurs. Depuisg
oui
peut légitimement changeri
en une chaîne, le moteur JavaScript ne peut pas simplement utiliser une addition numérique et une comparaison numérique dans la boucle, mais doit à chaque passage dans la boucle vérifier si l'un des appels de fonction a effectué quoi que ce soiti
oug
. En revanche, dans le dialecte "use strict" [un peu sain], le moteur JavaScipt peut examiner le code ci-dessus et savoir que chaque passage de la boucle utilise la même variable numérique et appelle la même fonction. Il suffira donc d'identifieri
et de fonctionnerg
une fois, plutôt que de devoir les regarder à chaque passage dans la boucle - un gain de temps considérable.la source
Eh bien, il existe des réponses assez professionnelles ici, celle-ci n’en est pas proche mais pourrait être intuitive pour vous.
Vous avez peut-être souvent entendu dire que lorsque vous avez besoin d'exécuter une tâche aussi rapidement que possible, vous souhaitez écrire le code qui l'exécute en assembleur. En effet, vous n'exécutez que les commandes dont vous avez réellement besoin pour terminer la tâche, et rien de plus. Si vous utilisez un langage de haut niveau, vous pouvez implémenter cette tâche sur plusieurs lignes, mais le compilateur doit toujours les traduire en langage machine. Cette traduction n'est pas toujours minimaliste car vous pourriez l'écrire directement. Cela signifie que la machine passera de nombreuses horloges à exécuter des commandes que vous pourriez épargner.
Bien que les compilateurs soient très sophistiqués, ils ne sont toujours pas aussi efficaces que les meilleurs programmeurs d’assemblage.
Poursuivant dans cette direction, le nombre de commandes inutiles augmente (généralement) à mesure que le langage est de niveau supérieur. (ce n'est pas vrai à 100% pour toutes les langues de haut niveau)
Donc, pour moi, la langue X est plus rapide que la langue Y (au moment de l'exécution) si, pour certains morceaux de code, le code machine de X est plus court que Y.
la source
Il est difficile de répondre définitivement à cette question car elle est si complexe et multidimensionnelle (c'est presque comme par exemple comparer des marques de voitures sur plusieurs critères), mais il existe de nouvelles études scientifiques comprenant un excellent référentiel de code connu sous le nom de code Rosetta ( aperçu de wikipedia ). Cette enquête 2014 par Nanz et Furia étudie cette question de manière tout à fait définitive et scientifique sur la base des critères typiques suivants et d’une analyse quantitative rare de qualités de code typiquement subjectives. L'abrégé contient des constatations et des généralisations fondées objectivement. (J'espère que d'autres études s'appuyant sur ces résultats pourront être réalisées à l'avenir.)
RQ1. Quels langages de programmation permettent un code plus concis?
RQ2. Quels langages de programmation compiler dans des exécutables plus petits?
RQ3. Quels langages de programmation ont de meilleures performances en temps d'exécution?
RQ4. Quels langages de programmation utilisent la mémoire plus efficacement?
RQ5. Quels langages de programmation sont moins sujets aux erreurs?
la source
Les langages informatiques ne sont qu'une abstraction de commandes pour expliquer à l'ordinateur ce qu'il doit faire.
Vous pouvez même écrire en langage informatique
Python
et le compiler avec un compilateur C (cython).Garder cela à l'esprit, la vitesse des langages informatiques ne peut être comparée.
Mais vous pouvez comparer les compilateurs pour le même langage dans une certaine mesure. Par exemple
GNU C
compilateur contreIntel C
compilateur. (Recherche du benchmark du compilateur)la source