J'ai googlé et fouillé sur le site Web de Go, mais je n'arrive pas à trouver d'explication pour les temps de construction extraordinaires de Go. S'agit-il de produits du langage (ou de leur absence), d'un compilateur hautement optimisé ou d'autre chose? Je n'essaie pas de promouvoir Go; Je suis juste curieux.
performance
compiler-construction
build-process
go
Evan Kroske
la source
la source
Réponses:
Analyse des dépendances.
La FAQ Go contenait la phrase suivante:
Bien que la phrase ne soit plus dans la FAQ, ce sujet est développé dans le discours Go de Google , qui compare l'approche d'analyse de dépendance de C / C ++ et Go.
C'est la raison principale d'une compilation rapide. Et c'est par conception.
la source
Je pense que ce n'est pas que les compilateurs Go sont rapides , c'est que les autres compilateurs sont lents .
Les compilateurs C et C ++ doivent analyser d'énormes quantités d'en-têtes - par exemple, la compilation de C ++ "hello world" nécessite la compilation de 18k lignes de code, ce qui représente presque un demi-mégaoctet de sources!
Les compilateurs Java et C # s'exécutent dans une machine virtuelle, ce qui signifie qu'avant de pouvoir compiler quoi que ce soit, le système d'exploitation doit charger la machine virtuelle entière, puis ils doivent être compilés JIT du bytecode au code natif, ce qui prend un certain temps.
La vitesse de compilation dépend de plusieurs facteurs.
Certaines langues sont conçues pour être compilées rapidement. Par exemple, Pascal a été conçu pour être compilé à l'aide d'un compilateur en un seul passage.
Les compilateurs eux-mêmes peuvent également être optimisés. Par exemple, le compilateur Turbo Pascal a été écrit dans un assembleur optimisé à la main, ce qui, combiné à la conception du langage, a abouti à un compilateur très rapide fonctionnant sur du matériel de classe 286. Je pense que même maintenant, les compilateurs Pascal modernes (par exemple FreePascal) sont plus rapides que les compilateurs Go.
la source
Il existe plusieurs raisons pour lesquelles le compilateur Go est beaucoup plus rapide que la plupart des compilateurs C / C ++:
Raison principale : la plupart des compilateurs C / C ++ présentent des conceptions exceptionnellement mauvaises (du point de vue de la vitesse de compilation). De plus, du point de vue de la vitesse de compilation, certaines parties de l'écosystème C / C ++ (telles que les éditeurs dans lesquels les programmeurs écrivent leurs codes) ne sont pas conçues en fonction de la vitesse de compilation.
Principale raison : la vitesse de compilation rapide était un choix conscient dans le compilateur Go et aussi dans le langage Go
Le compilateur Go a un optimiseur plus simple que les compilateurs C / C ++
Contrairement à C ++, Go n'a pas de modèles ni de fonctions en ligne. Cela signifie que Go n'a pas besoin d'effectuer d'instanciation de modèle ou de fonction.
Le compilateur Go génère plus tôt le code assembleur de bas niveau et l'optimiseur fonctionne sur le code assembleur, tandis que dans un compilateur C / C ++ typique, l'optimisation passe le travail sur une représentation interne du code source d'origine. La surcharge supplémentaire dans le compilateur C / C ++ vient du fait que la représentation interne doit être générée.
La liaison finale (5l / 6l / 8l) d'un programme Go peut être plus lente que la liaison d'un programme C / C ++, car le compilateur Go parcourt tout le code assembleur utilisé et peut-être qu'il effectue également d'autres actions supplémentaires que C / C ++ les éditeurs de liens ne font pas
Certains compilateurs C / C ++ (GCC) génèrent des instructions sous forme de texte (à transmettre à l'assembleur), tandis que le compilateur Go génère des instructions sous forme binaire. Un travail supplémentaire (mais pas beaucoup) doit être effectué afin de transformer le texte en binaire.
Le compilateur Go ne cible qu'un petit nombre d'architectures CPU, tandis que le compilateur GCC cible un grand nombre de CPU
Les compilateurs qui ont été conçus dans le but d'une vitesse de compilation élevée, tels que Jikes, sont rapides. Sur un processeur à 2 GHz, Jikes peut compiler plus de 20000 lignes de code Java par seconde (et le mode de compilation incrémentiel est encore plus efficace).
la source
L'efficacité de la compilation était un objectif de conception majeur:
La FAQ sur la langue est assez intéressante en ce qui concerne les fonctionnalités de langue spécifiques liées à l'analyse:
la source
aType
s'agissait d'une référence de variable, et plus tard dans la phase d'analyse sémantique lorsque vous découvrez que vous n'imprimez pas une erreur significative à ce moment-là.Bien que la plupart de ce qui précède soit vrai, il y a un point très important qui n'était pas vraiment mentionné: la gestion des dépendances.
Go doit uniquement inclure les packages que vous importez directement (comme ceux déjà importés dont ils ont besoin). C'est en contraste frappant avec C / C ++, où chaque fichier commence avec x en-têtes, qui incluent y en-têtes, etc.
la source
L'auto-compilation est un bon test pour l'efficacité de traduction d'un compilateur: combien de temps faut-il à un compilateur donné pour se compiler? Pour C ++, cela prend beaucoup de temps (heures?). Par comparaison, un compilateur Pascal / Modula-2 / Oberon se compilerait en moins d' une seconde sur une machine moderne [1].
Go a été inspiré par ces langues, mais certaines des principales raisons de cette efficacité incluent:
Une syntaxe clairement définie et mathématiquement saine, pour un balayage et une analyse efficaces.
Un langage de type sécurisé et compilé statiquement qui utilise une compilation séparée avec dépendance et vérification de type à travers les limites du module, pour éviter la relecture inutile des fichiers d'en-tête et la recompilation d'autres modules - par opposition à une compilation indépendante comme en C / C ++ où aucune vérification inter-modules de ce type n'est effectuée par le compilateur (d'où la nécessité de relire tous ces fichiers d'en-tête encore et encore, même pour un simple programme "hello world" sur une seule ligne).
Une implémentation efficace du compilateur (par exemple, analyse descendante à passage unique, descente récursive) - ce qui bien sûr est grandement aidé par les points 1 et 2 ci-dessus.
Ces principes ont déjà été connus et pleinement mis en œuvre dans les années 1970 et 1980 dans des langues comme Mesa, Ada, Modula-2 / Oberon et plusieurs autres, et ne font que maintenant (dans les années 2010) leur chemin vers des langues modernes comme Go (Google) , Swift (Apple), C # (Microsoft) et plusieurs autres.
Espérons que ce sera bientôt la norme et non l'exception. Pour y arriver, deux choses doivent se produire:
Premièrement, les fournisseurs de plates-formes logicielles telles que Google, Microsoft et Apple devraient commencer par encourager les développeurs d' applications à utiliser la nouvelle méthodologie de compilation, tout en leur permettant de réutiliser leur base de code existante. C'est ce qu'Apple essaie maintenant de faire avec le langage de programmation Swift, qui peut coexister avec Objective-C (car il utilise le même environnement d'exécution).
Deuxièmement, les plates-formes logicielles sous-jacentes elles-mêmes devraient éventuellement être réécrites au fil du temps en utilisant ces principes, tout en repensant simultanément la hiérarchie des modules dans le processus pour les rendre moins monolithiques. C'est bien sûr une tâche gigantesque et pourrait bien prendre la majeure partie d'une décennie (s'ils sont assez courageux pour le faire - ce que je ne suis pas du tout sûr dans le cas de Google).
Dans tous les cas, c'est la plate-forme qui stimule l'adoption du langage, et non l'inverse.
Références:
[1] http://www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.System.pdf , page 6: "Le compilateur se compile en 3 secondes environ". Cette citation est pour une carte de développement FPGA Xilinx Spartan-3 à faible coût fonctionnant à une fréquence d'horloge de 25 MHz et disposant de 1 Mo de mémoire principale. De celui-ci peut facilement extrapoler à "moins de 1 seconde" pour un processeur moderne fonctionnant à une fréquence d'horloge bien au-dessus de 1 GHz et plusieurs Go de mémoire principale (c'est-à-dire plusieurs ordres de grandeur plus puissants que la carte FPGA Xilinx Spartan-3), même en tenant compte des vitesses d'E / S. Déjà en 1990, quand Oberon était exécuté sur un processeur NS32X32 à 25 MHz avec 2-4 Mo de mémoire principale, le compilateur s'est compilé en quelques secondes. La notion d' attendre réellementpour que le compilateur termine un cycle de compilation était complètement inconnu des programmeurs Oberon même à l'époque. Pour les programmes typiques, il a toujours fallu plus de temps pour retirer le doigt du bouton de la souris qui a déclenché la commande de compilation que d'attendre que le compilateur termine la compilation qui vient d'être déclenchée. C'était une satisfaction vraiment instantanée, avec des temps d'attente presque nuls. Et la qualité du code produit, même si elle n'était pas toujours complètement comparable aux meilleurs compilateurs disponibles à l'époque, était remarquablement bonne pour la plupart des tâches et tout à fait acceptable en général.
la source
Go a été conçu pour être rapide, et ça se voit.
Notez que GO n'est pas le seul langage avec de telles fonctionnalités (les modules sont la norme dans les langages modernes), mais ils l'ont bien fait.
la source
Extrait du livre " The Go Programming Language " d'Alan Donovan et Brian Kernighan:
la source
L'idée de base de la compilation est en fait très simple. Un analyseur à descente récursive, en principe, peut fonctionner à une vitesse liée aux E / S. La génération de code est fondamentalement un processus très simple. Une table de symboles et un système de type de base ne demandent pas beaucoup de calculs.
Cependant, il n'est pas difficile de ralentir un compilateur.
S'il y a une phase de préprocesseur, avec des directives d' inclusion à plusieurs niveaux , des définitions de macro et une compilation conditionnelle, aussi utiles que cela soit, il n'est pas difficile de la charger. (Par exemple, je pense aux fichiers d'en-tête Windows et MFC.) C'est pourquoi des en-têtes précompilés sont nécessaires.
En termes d'optimisation du code généré, il n'y a pas de limite à la quantité de traitement pouvant être ajoutée à cette phase.
la source
Simplement (selon mes propres mots), car la syntaxe est très simple (à analyser et à analyser)
Par exemple, pas d'héritage de type signifie, pas d'analyse problématique pour savoir si le nouveau type suit les règles imposées par le type de base.
Par exemple dans cet exemple de code: "interfaces" le compilateur ne va pas vérifier si le type prévu implémente l'interface donnée lors de l'analyse de ce type. Ce n'est que jusqu'à son utilisation (et SI elle est utilisée) que la vérification est effectuée.
Autre exemple, le compilateur vous indique si vous déclarez une variable et ne l'utilisez pas (ou si vous êtes censé contenir une valeur de retour et que vous ne l'êtes pas)
Ce qui suit ne se compile pas:
Ce genre d’applications et principes rend le code résultant plus sûr, et le compilateur n'a pas à effectuer de validations supplémentaires que le programmeur peut effectuer.
Dans l'ensemble, tous ces détails facilitent l'analyse d'un langage, ce qui se traduit par des compilations rapides.
Encore une fois, selon mes propres mots.
la source
Je pense que Go a été conçu en parallèle avec la création de compilateurs, ils étaient donc les meilleurs amis de la naissance. (OMI)
la source
Quoi d'autre?
la source