Je me demande s’il est possible de construire des compilateurs pour des langages dynamiques comme Ruby afin d’avoir des performances similaires et comparables à celles du C / C ++? D'après ce que je comprends des compilateurs, prenons Ruby par exemple, compiler du code Ruby ne peut jamais être efficace, car Ruby gère la réflexion, des fonctionnalités telles que la conversion automatique de type d'un entier à un grand, et l'absence de typage statique rendent la construction d'un compilateur efficace. pour Ruby extrêmement difficile.
Est-il possible de construire un compilateur capable de compiler Ruby ou tout autre langage dynamique en un binaire fonctionnant de manière très proche de C / C ++? Existe-t-il une raison fondamentale pour laquelle les compilateurs JIT, tels que PyPy / Rubinius, finiront par ne jamais être plus performants que C / C ++?
Remarque: je comprends que la «performance» puisse être vague, donc pour clarifier cela, je voulais dire, si vous pouvez utiliser X en C / C ++ avec la performance Y, pouvez-vous utiliser X en Ruby / Python avec une performance proche de Y? Où X représente tout, des pilotes de périphérique et du code de système d'exploitation aux applications Web.
Réponses:
À tous ceux qui ont dit «oui», je vais proposer que la réponse soit «non», à dessein . Ces langages ne seront jamais capables de rivaliser avec les performances des langages compilés statiquement.
Kos a déclaré (très valable) que les langages dynamiques ont plus d'informations sur le système à l'exécution, ce qui peut être utilisé pour optimiser le code.
Cependant, il y a un autre côté de la médaille: ces informations supplémentaires doivent être conservées. Sur les architectures modernes, ceci est un tueur de performance.
William Edwards offre un bon aperçu de l'argumentation .
En particulier, les optimisations mentionnées par Kos ne peuvent être appliquées au-delà d'une portée très limitée, sauf si vous limitez de manière drastique le pouvoir d'expression de vos langues, comme l'a mentionné Devin. C’est bien sûr un compromis viable, mais aux fins de la discussion, vous vous retrouvez avec un langage statique et non dynamique. Ces langues diffèrent fondamentalement de Python ou de Ruby comme le comprendraient la plupart des gens.
William cite quelques diapositives IBM intéressantes :
Certaines de ces vérifications peuvent être éliminées après analyse (NB: cette analyse prend également du temps - au moment de l'exécution).
En outre, Kos affirme que les langages dynamiques pourraient même surpasser les performances en C ++. JIT peut en effet analyser le comportement du programme et appliquer des optimisations appropriées.
Mais les compilateurs C ++ peuvent faire la même chose! Les compilateurs modernes offrent ce que l’on appelle l’optimisation guidée par le profil qui, s’ils reçoivent les données appropriées, permet de modéliser le comportement d’exécution du programme et d’appliquer les mêmes optimisations qu’un JIT.
Bien sûr, tout dépend de l’existence de données d’entraînement réalistes et, en outre, le programme ne peut pas adapter ses caractéristiques d’exécution si le modèle d’utilisation change en cours d’exécution. Les JIT peuvent théoriquement gérer cela. Cela m'intéresserait de voir comment cela se passera dans la pratique, car pour basculer les optimisations, le JIT devrait continuellement collecter des données d'utilisation, ce qui ralentit encore une fois l'exécution.
En résumé, je ne suis pas convaincu que les optimisations de points chauds d'exécution compensent les frais généraux liés au suivi des informations d'exécution à long terme , par rapport à l'analyse et à l'optimisation statiques.
la source
javac
optimisation guidée par le profil a- t-elle déjà eu lieu ? Pas autant que je sache. En général, il n’a aucun sens de faire en sorte que le compilateur d’un langage JITted soit bien optimisé, car le JIT peut le gérer (et à tout le moins, plus de langues tireront profit de cet effort). Donc (ce qui est compréhensible), l'javac
optimiseur n'a jamais fait l'objet de beaucoup d'efforts , pour autant que je sache (pour les langages .NET, c'est absolument vrai).Oui. Prenons, par exemple, PyPy. C'est une collection de code Python qui exécute une interprétation proche de C (pas si proche, mais pas si loin non plus). Pour ce faire, il effectue une analyse complète du programme sur le code source afin d’attribuer un type statique à chaque variable (voir les documents Annotator et Rtyper pour plus de détails), puis, une fois doté des mêmes informations de type que C, il peut effectuer le même sortes d'optimisations. Au moins en théorie.
Le compromis est bien sûr que RPython n'accepte qu'un sous-ensemble de code Python et, en général, même si cette restriction est levée, seul un sous-ensemble de code Python peut fonctionner correctement: le sous-ensemble pouvant être analysé et doté de types statiques.
Si vous limitez suffisamment Python, vous pouvez créer des optimiseurs exploitant le sous-ensemble restreint et le compilant en code efficace. Ce n'est pas vraiment un avantage intéressant, en fait, c'est bien connu. Mais l’intérêt premier d’utiliser Python (ou Ruby) au départ était que nous voulions utiliser des fonctionnalités intéressantes qui analysent peut-être mal et donnent de bonnes performances! Donc, la question intéressante est en fait ...
Nah.
Je veux dire par là: bien sûr, au fur et à mesure que le code s'accumule, vous pouvez obtenir suffisamment d'informations de frappe et suffisamment de zones réactives pour compiler l'intégralité du code en code machine. Et peut-être que nous pouvons obtenir que cela fonctionne mieux que C pour certains codes. Je ne pense pas que ce soit extrêmement controversé. Mais il doit encore "s'échauffer" et les performances sont encore un peu moins prévisibles. Elles ne seront pas aussi performantes que le C ou le C ++ pour certaines tâches nécessitant des performances élevées de manière constante et prévisible.
Les données de performances existantes pour Java, qui contiennent à la fois plus d'informations sur les types que Python ou Ruby, et un compilateur JIT mieux développé que Python ou Ruby, ne correspondent toujours pas à C / C ++. Il est cependant dans le même stade.
la source
La réponse courte est: nous ne savons pas , demandez à nouveau dans 100 ans. (Nous pourrions toujours ne pas savoir alors; peut-être que nous ne le saurons jamais.)
En théorie, c'est possible. Prenez tous les programmes jamais écrits, convertissez-les manuellement en code machine le plus efficace possible et écrivez un interpréteur qui mappe les codes sources en codes machines. Cela est possible car seul un nombre fini de programmes a été écrit (et au fur et à mesure que de nouveaux programmes sont écrits, maintenez les traductions manuelles). Ceci est aussi, bien sûr, complètement idiot sur le plan pratique.
Là encore, en théorie, les langages de haut niveau pourraient atteindre les performances du code machine, mais ils ne les dépasseront pas. C'est encore très théorique, car dans la pratique, nous avons très rarement recours à l'écriture de code machine. Cet argument ne s'applique pas à la comparaison de langages de niveau supérieur: cela n'implique pas que C doit être plus efficace que Python, seul ce code machine ne peut pas faire pire que Python.
Venant de l’autre côté, à titre expérimental, nous pouvons constater que la plupart du temps , les langages de haut niveau interprétés ont des performances pires que les langages de bas niveau compilés. Nous avons tendance à écrire du code non sensible au temps dans des langages de très haut niveau et des boucles internes à temps critique dans un assemblage, avec des langages comme C et Python se situant entre les deux. Bien que je ne dispose d'aucune statistique à ce sujet, je pense que c'est la meilleure décision dans la plupart des cas.
Cependant, il existe des cas non contestés où les langages de haut niveau surpassent le code que l'on rédigerait de manière réaliste: les environnements de programmation spéciaux. Des programmes comme Matlab et Mathematica sont souvent bien meilleurs pour résoudre certains types de problèmes mathématiques que ce que de simples mortels peuvent écrire. Les fonctions de la bibliothèque ont peut-être été écrites en C ou C ++ (ce qui alimente le camp «Les langages de bas niveau sont plus efficaces»), mais ça ne me regarde pas si j'écris du code Mathematica, la bibliothèque est une boîte noire.
Est-il théoriquement possible que Python soit aussi proche, voire plus proche, de performances optimales que C? Comme on l'a vu ci-dessus, oui, mais nous en sommes très loin aujourd'hui. Là encore, les compilateurs ont fait beaucoup de progrès au cours des dernières décennies, et ces progrès ne ralentissent pas.
Les langages de haut niveau ont tendance à automatiser davantage les tâches. Ils ont donc plus de travail à effectuer et ont donc tendance à être moins efficaces. D'un autre côté, ils ont tendance à avoir plus d'informations sémantiques, il est donc plus facile de repérer les optimisations (si vous écrivez un compilateur Haskell, vous n'avez pas à craindre qu'un autre thread modifie une variable sous votre nez). L'un des nombreux efforts visant à comparer des
pommes et des oranges avecdifférents langages de programmation est le jeu de tests de langage informatique (anciennement connu sous le nom de fusillade). Fortran a tendance à briller lors de tâches numériques; mais quand il s'agit de manipuler des données structurées ou une commutation de thread à haut débit, F # et Scala se débrouillent bien. Ne prenez pas ces résultats comme des évangiles: une grande partie de ce qu'ils mesurent est la qualité de l'auteur du programme de test dans chaque langue.Un argument en faveur des langages de haut niveau est que la performance sur les systèmes modernes n’est pas aussi fortement corrélée au nombre d’instructions exécutées, et moins au fil du temps. Les langages de bas niveau conviennent parfaitement aux machines séquentielles simples. Si un langage de haut niveau exécute deux fois plus d'instructions, mais parvient à utiliser le cache de manière plus intelligente, de sorte qu'il en divise par deux le nombre d'omissions manquantes dans le cache, le vainqueur peut en résulter.
Sur les plates-formes de serveur et de bureau, les processeurs ont presque atteint un plateau où ils ne vont pas plus vite (les plates-formes mobiles y parviennent aussi); cela favorise les langues où le parallélisme est facile à exploiter. Beaucoup de processeurs passent le plus clair de leur temps à attendre une réponse d’entrée / sortie; le temps passé en calcul importe peu par rapport à la quantité d'E / S, et un langage permettant au programmeur de minimiser les communications est un avantage.
Dans l’ensemble, si les langues de haut niveau commencent par une pénalité, elles ont plus de marge de progression. À quel point peuvent-ils se rapprocher? Demander à nouveau dans 100 ans.
Note finale: souvent, la comparaison n’est pas entre le programme le plus efficace pouvant être écrit en langue A et le même dans le langage B, ni entre le programme le plus efficace jamais écrit dans chaque langue, mais entre le programme le plus efficace qui puisse être écrit par un humain dans un certain temps dans chaque langue. Cela introduit un élément qui ne peut pas être analysé mathématiquement, même en principe. Concrètement, cela signifie souvent que la meilleure performance est un compromis entre le niveau de code de bas niveau que vous devez écrire pour atteindre les objectifs de performance et le temps que vous avez le temps d'écrire pour respecter les dates de parution.
la source
La différence fondamentale entre la déclaration C ++
x = a + b
et l'instruction Pythonx = a + b
est qu'un compilateur C / C ++ peut dire de cette déclaration (et un peu d' informations supplémentaires qu'il a facilement disponible sur les types dex
,a
etb
) précisément ce que le code machine doit être exécutée . Tandis que pour dire quelles opérations l’instruction Python va effectuer, vous devez résoudre le problème Halting.En C, cette instruction compilera essentiellement l'un des quelques types d'ajout de machine (et le compilateur C sait lequel). En C ++, cette méthode peut être compilée ou appelée à appeler une fonction connue de manière statique, ou (dans le pire des cas), elle doit peut-être être compilée en une méthode de recherche et d'appel virtuelle, même si celle-ci entraîne une surcharge de code machine assez réduite. Plus important encore, le compilateur C ++ peut dire, à partir des types connus statiquement impliqués, s'il peut émettre une seule opération d'addition rapide ou s'il doit utiliser l'une des options plus lentes.
En Python, un compilateur pourrait théoriquement faire presque ce bien si elle savait que
a
etb
étaient tous les deuxint
s. Il y a une surcharge de boxe supplémentaire, mais si les types étaient connus statiquement, vous pourriez probablement vous en débarrasser aussi (tout en présentant l'interface, les entiers sont des objets avec des méthodes, une hiérarchie de super-classes, etc.). Le problème est un compilateur pour Python ne peut passachez cela, car les classes sont définies à l'exécution, peuvent être modifiées à l'exécution, et même les modules qui définissent et importent sont résolus à l'exécution (et même les instructions d'importation exécutées dépendent d'éléments connus uniquement lors de l'exécution). Le compilateur Python devrait donc savoir quel code a été exécuté (c'est-à-dire résoudre le problème de l'arrêt) afin de savoir ce que l'instruction en cours de compilation fera.Ainsi, même avec les analyses les plus sophistiquées qui sont théoriquement possibles , vous ne pouvez tout simplement pas en dire beaucoup sur ce qu’une déclaration Python va faire à l’avance. Cela signifie que même si un compilateur Python sophistiqué était implémenté, il devrait toujours émettre du code machine conforme au protocole de recherche dans le dictionnaire Python pour déterminer la classe d'un objet et trouver des méthodes (passant par le MRO de la hiérarchie de classes). qui peut aussi changer de façon dynamique au moment de l’exécution et est donc difficile à compiler dans une simple table de méthode virtuelle) et fait essentiellement ce que font les interprètes (lents). C'est pourquoi il n'existe pas vraiment de compilateurs d'optimisation sophistiqués pour les langages dynamiques. Ce n'est pas simplement difficile d'en créer un, le gain maximum possible n'est pas
Notez que cela ne repose pas sur ce que le code est fait, il est basé sur ce que le code pourrait faire. Même le code Python, qui est une simple série d'opérations arithmétiques sur nombres entiers, doit être compilé comme s'il appelait des opérations de classe arbitraires. Les langages statiques imposent de plus grandes restrictions quant aux possibilités d'utilisation du code et, par conséquent, leurs compilateurs peuvent faire davantage d'hypothèses.
Les compilateurs JIT gagnent sur ce point en attendant le moment de l'exécution pour compiler / optimiser. Cela leur permet d' émettre un code qui fonctionne pour ce que le code est en train de faire plutôt que ce qu'il pourrait faire. Et à cause de cela, les compilateurs JIT ont un potentiel de gain beaucoup plus important pour les langages dynamiques que pour les langages statiques; pour des langages plus statiques, une bonne partie de ce qu'un optimiseur aimerait savoir peut être connue à l'avance. Vous pouvez donc aussi l'optimiser, laissant ainsi moins de choses à un compilateur JIT.
Il existe différents compilateurs JIT pour langages dynamiques qui prétendent atteindre des vitesses d’exécution comparables à celles du C / C ++ compilé et optimisé. Il existe même des optimisations pouvant être effectuées par un compilateur JIT qui ne peuvent pas être effectuées par un compilateur en avance pour n'importe quel langage. Ainsi, en théorie, la compilation JIT (pour certains programmes) pourrait un jour dépasser le meilleur compilateur statique possible. Mais comme Devin l'a fait remarquer à juste titre, les propriétés de la compilation JIT (seuls les "hotspots" sont rapides et uniquement après une période de préchauffage) signifient qu'il est peu probable que les langages dynamiques compilés par JIT soient adaptés à toutes les applications possibles, même s'ils deviennent aussi vite ou plus rapidement que les langages compilés statiquement en général.
la source
foo = x + y
où la prédiction du comportement de l'opérateur d'addition lors de la compilation dépend de la résolution du problème d'arrêt.x + y
des opérations d’ajout de machine efficaces, vous devez savoir au moment de la compilation s’il s’agit ou non. Tout le temps , pas seulement de temps en temps. Pour les langages dynamiques, cela n’est presque jamais possible avec des programmes réalistes, même si une heuristique raisonnable suppose une réponse exacte la plupart du temps. La compilation nécessite des garanties lors de la compilation . Donc, en parlant de "dans de nombreuses circonstances", vous ne répondez pas du tout à ma réponse.Juste un pointeur rapide décrivant le pire scénario pour les langages dynamiques:
En conséquence, Perl (complet) ne peut jamais être compilé de manière statique.
En général, comme toujours, cela dépend. Je suis convaincu que si vous essayez d'émuler des caractéristiques dynamiques dans un langage compilé de manière statique, des interpréteurs bien conçus ou des variantes (partiellement) compilées peuvent se rapprocher ou saper les performances des langages compilés de manière statique.
Un autre point à garder à l'esprit est que les langages dynamiques résolvent un autre problème que le C. Le C est à peine une belle syntaxe pour l'assembleur, alors que les langages dynamiques offrent des abstractions riches. Les performances d'exécution ne sont souvent pas la principale préoccupation: le délai de mise sur le marché, par exemple, dépend de la capacité de vos développeurs à écrire des systèmes complexes et de grande qualité dans des délais très courts. L'extensibilité sans recompilation, par exemple avec des plugins, est une autre fonctionnalité populaire. Quelle langue préférez-vous dans ces cas?
la source
Pour tenter d'apporter une réponse plus objectivement scientifique à cette question, je discute comme suit. Un langage dynamique nécessite un interprète, ou une exécution, pour prendre des décisions au moment de l'exécution. Cet interpréteur, ou exécution, est un programme informatique et, en tant que tel, a été écrit dans un langage de programmation statique ou dynamique.
Si l'interprète / le moteur d'exécution est écrit dans un langage statique, vous pouvez alors écrire un programme dans ce langage statique qui (a) remplit la même fonction que le programme dynamique qu'il interprète et (b) effectue au moins aussi bien. Espérons que cela va de soi, car fournir une preuve rigoureuse de ces affirmations nécessiterait des efforts supplémentaires (voire considérables).
En supposant que ces affirmations soient vraies, la seule solution consiste à exiger que l'interpréteur / runtime soit également écrit dans un langage dynamique. Cependant, nous rencontrons le même problème qu'auparavant: si l'interpréteur est dynamique, il nécessite un interpréteur / runtime, qui doit également avoir été écrit dans un langage de programmation, dynamique ou statique.
Sauf si vous supposez qu'une instance d'un interprète est capable de s'interpréter elle-même à l'exécution (j'espère que cela est évidemment absurde), le seul moyen de vaincre les langues statiques est que chaque instance d'interprète soit interprétée par une instance distincte d'interprète; cela mène soit à une régression infinie (j'espère que cela est évidemment absurde), soit à une boucle d'interprètes fermée (j'espère que cela est également évidemment absurde).
Il semble donc que même en théorie, les langages dynamiques ne fonctionnent pas mieux que les langages statiques en général. Lorsque vous utilisez des modèles d’ordinateurs réalistes, cela semble encore plus plausible; Après tout, une machine ne peut exécuter que des séquences d'instructions machine et toutes les séquences d'instructions machine peuvent être compilées de manière statique.
En pratique, pour faire correspondre les performances d'un langage dynamique à un langage statique, il peut être nécessaire de réimplémenter l'interpréteur / runtime dans un langage statique. Cependant, le fait que vous puissiez le faire est l’essentiel de cet argument. C'est une question de poule et d'oeuf et, si vous êtes d'accord avec les hypothèses non prouvées (bien que, à mon avis, la plupart du temps évidentes d'elles-mêmes) faites ci-dessus, nous pouvons réellement y répondre; nous devons donner le feu vert aux langages statiques et non dynamiques.
Une autre façon de répondre à la question, à la lumière de cette discussion, est la suivante: dans le modèle programmé à calcul stocké, control = data, qui est au cœur de l’informatique moderne, la distinction entre compilation statique et compilation dynamique est une fausse dichotomie; Les langages compilés statiquement doivent avoir un moyen de générer et d’exécuter du code arbitraire au moment de l’exécution. C'est fondamentalement lié au calcul universel.
la source
main(args) { for ( i=0; i<1000000; i++ ) { if ( args[0] == "1" ) {...} else {...} }
peut être considérablement accéléré une fois la valeur deargs
connue (en supposant qu'il ne change jamais, ce que nous pourrons peut-être affirmer). Un compilateur statique ne peut pas créer de code qui supprime la comparaison. (Bien sûr, dans cet exemple, vous sortez simplementif
de la boucle. Mais la chose peut être plus compliquée.)Je pense que la réponse est "oui" . Je pense aussi qu’ils peuvent même dépasser l’architecture actuelle C / C ++ en termes d’efficacité (même légèrement).
La raison est simple: il y a plus d'informations à l'exécution qu'à la compilation.
Les types dynamiques ne sont qu'un léger obstacle: si une fonction est toujours ou presque toujours exécutée avec les mêmes types d'arguments, un optimiseur JIT peut générer une branche et un code machine pour ce cas spécifique. Et il y a tellement plus qui peut être fait.
Voir Dynamic Languages Strike Back , un discours de Steve Yegge de Google (il existe également une version vidéo quelque part, je crois). Il mentionne des techniques concrètes d'optimisation JIT de la V8. Inspirant!
J'attends avec impatience ce que nous aurons dans les 5 prochaines années!
la source
Les personnes qui pensent que cela est théoriquement possible, ou dans un futur lointain, ont complètement tort, à mon avis. Le problème réside dans le fait que les langages dynamiques fournissent et imposent un style de programmation totalement différent. En réalité, la différence est double, même si les deux aspects sont liés:
Le deuxième point fournit la généricité gratuitement. Notez que les structures ici sont des éléments composites, des collections, mais aussi des types eux-mêmes, et même (!) Des routines de toutes sortes (fonctions, actions, opérations) ... Nous pourrions taper des structures par leurs types d'élément, mais en raison du premier point vérifier aurait lieu à l'exécution de toute façon. Nous aurions pu taper des symboles tout en conservant ceux structurés sans les typer en fonction de leurs types d’éléments (un tableau
a
serait simplement typé comme un tableau et non comme un tableau d’entiers), mais même cela n’est pas vrai dans un langage dynamique (a
pourrait aussi bien contenir un string).Element
Element
Il est clair pour moi qu’il s’agit là d’une pénalité énorme. et je ne touche même pas à toutes les conséquences (la myriade de vérifications d'exécution de toutes sortes nécessaires pour assurer la sensibilité du programme) bien décrites dans d'autres publications.
la source
Je n'ai pas eu le temps de lire toutes les réponses en détail ... mais j'étais amusé.
Une controverse similaire a eu lieu dans les années soixante et au début des années soixante-dix (l'histoire de l'informatique se répète souvent): peut-on compiler des langages de haut niveau pour produire un code aussi efficace que le code machine, disons le code assembleur, produit manuellement par un programmeur. Tout le monde sait qu'un programmeur est beaucoup plus intelligent que n'importe quel programme et peut proposer une optimisation très intelligente (en pensant principalement à ce qu'on appelle maintenant l'optimisation du judas). C'est bien sûr ironie de ma part.
Il y avait même un concept d'expansion du code: le rapport entre la taille du code produit par un compilateur et la taille du code du même programme produit par un bon programmeur (comme s'il y en avait eu trop :-). Bien entendu, l'idée était que ce rapport était toujours supérieur à 1. Les langues de l'époque étaient le cobol et le fortran 4, ou l'algol 60 pour les intellectuels. Je crois que Lisp n'a pas été considéré.
Il y avait des rumeurs selon lesquelles quelqu'un aurait produit un compilateur pouvant parfois obtenir un taux d'expansion égal à 1 ... jusqu'à ce qu'il devienne simplement la règle voulant que le code compilé soit bien meilleur que le code écrit à la main (et plus fiable également). Les gens étaient inquiets à propos de la taille du code à cette époque (petits souvenirs), mais il en va de même pour la vitesse ou la consommation d’énergie. Je ne vais pas entrer dans les raisons.
Les fonctionnalités étranges, les fonctionnalités dynamiques d'une langue importent peu. Ce qui compte, c'est la manière dont ils sont utilisés, qu'ils soient utilisés ou non. Les performances, quelle que soit l’unité (taille du code, vitesse, énergie, ...) dépendent souvent de très petites parties des programmes. Il y a donc de fortes chances pour que les installations qui donnent un pouvoir d'expression ne gênent pas vraiment. Avec de bonnes pratiques de programmation, les installations de pointe ne sont utilisées que de manière disciplinée, pour imaginer de nouvelles structures (c'était la leçon à tirer).
Le fait qu'une langue ne comporte pas de typage statique n'a jamais signifié que les programmes écrits dans cette langue ne sont pas typés de manière statique. D'autre part, il se peut que le système de types utilisé par un programme ne soit pas encore suffisamment formalisé pour qu'un vérificateur de types existe maintenant.
Au cours de la discussion, il y a eu plusieurs références à l'analyse du cas le plus défavorable ("problème stoppant", analyse PERL). Mais l'analyse du cas le plus défavorable n'est généralement pas pertinente. Ce qui compte, c’est ce qui se passe dans la plupart des cas ou dans des cas utiles… qu’ils soient définis, compris ou vécus. Voici une autre histoire, directement liée à l'optimisation du programme. Cela s'est passé il y a longtemps dans une grande université du Texas, entre un doctorant et son conseiller (qui a ensuite été élu dans l'une des académies nationales). Si je me souviens bien, l’élève insistait pour étudier un problème d’analyse / optimisation que le conseiller avait montré impossible à résoudre. Bientôt, ils ne parlèrent plus. Mais l'étudiant avait raison: le problème était suffisamment facile à résoudre dans la plupart des cas pratiques pour que la thèse qu'il a produite devienne un ouvrage de référence.
Et pour commenter davantage la déclaration selon laquelle
Perl parsing is not computable
, quelle que soit la signification de cette phrase, il existe un problème similaire avec ML, qui est un langage remarquablement bien formalisé.Type checking complexity in ML is a double exponential in the lenght of the program.
C’est un résultat très précis et formel dans le pire des cas, ce qui n’a aucune importance. Après tout, les utilisateurs de ML attendent toujours un programme pratique qui fera exploser le vérificateur de type.Dans de nombreux cas, comme auparavant, le temps et la compétence de l'homme sont plus rares que la puissance de calcul.
Le vrai problème du futur sera de faire évoluer nos langages pour intégrer de nouvelles connaissances, de nouvelles formes de programmation, sans avoir à réécrire tous les logiciels existants qui sont encore utilisés.
Si vous regardez les mathématiques, c'est un très grand corpus de connaissances. Les langages utilisés pour l'exprimer, les notations et les concepts ont évolué au fil des siècles. Il est facile d’écrire d’anciens théorèmes avec les nouveaux concepts. Nous adaptons les preuves principales, mais ne vous inquiétez pas pour beaucoup de résultats.
Mais dans le cas de la programmation, il se peut que nous devions réécrire toutes les preuves à partir de zéro (les programmes sont des preuves). Peut-être avons-nous vraiment besoin de langages de programmation de très haut niveau et évolutifs. Les concepteurs d'optimisation seront heureux de suivre.
la source
Quelques notes:
Tous les langages de haut niveau ne sont pas dynamiques. Haskell est de très haut niveau, mais est entièrement typé de manière statique. Même les langages de programmation tels que Rust, Nim et D peuvent exprimer des abstractions de haut niveau de manière succincte et efficace. En fait, ils peuvent être aussi concis que des langages dynamiques.
Il existe des compilateurs extrêmement optimisés pour les langages dynamiques. Les implémentations Good Lisp atteignent la moitié de la vitesse de l’équivalent C.
La compilation JIT peut être une grande victoire ici. Le pare-feu d'applications Web de CloudFlare génère du code Lua exécuté par LuaJIT. LuaJIT optimise fortement les chemins d’exécution réellement empruntés (en général, les chemins non attaquants), de sorte que le code s’exécute beaucoup plus rapidement que le code produit par un compilateur statique sur la charge de travail réelle. Contrairement à un compilateur statique avec optimisation guidée par le profil, LuaJIT s’adapte aux modifications des chemins d’exécution lors de l’exécution.
La désoptimisation est également cruciale. Au lieu que le code compilé par JIT ait besoin de vérifier si une classe est monkeypatchée, l'acte monkeypatching déclenche un crochet dans le système d'exécution qui supprime le code machine qui reposait sur l'ancienne définition.
la source