Si j'ai bien compris, C/C++ produit du code natif à exécuter sur une architecture de machine particulière. Inversement, des langages comme Java et C # s'exécutent sur une machine virtuelle, ce qui éloigne l'architecture native. Logiquement, il semblerait impossible que Java ou C # corresponde à la vitesse du C++ à cause de cette étape intermédiaire. Cependant, on m'a dit que les derniers compilateurs ("points chauds") peuvent atteindre cette vitesse, voire dépasser. il.
C’est peut-être plus une question de compilateur que de question de langue, mais est-ce que quelqu'un peut expliquer en anglais simple comment il est possible pour l’une de ces langues de machine virtuelle d’être plus performante qu’une langue maternelle?
Généralement, C # et Java peuvent être tout aussi rapides ou plus rapides, car le compilateur JIT - un compilateur qui compile votre IL la première fois qu'il est exécuté - peut effectuer des optimisations qu'un programme compilé C++ ne peut pas car il peut interroger la machine. Il peut déterminer si la machine est Intel ou AMD; Pentium 4, Core Solo ou Core Duo; ou si prend en charge SSE4, etc.
Un programme C++ doit être préalablement compilé, généralement avec des optimisations mixtes, de sorte qu’il fonctionne correctement sur toutes les machines, sans être optimisé autant qu’il le pourrait pour une configuration unique (processeur, jeu d’instructions, autre matériel).
De plus, certaines fonctionnalités du langage permettent au compilateur dans C # et Java de formuler des hypothèses sur votre code qui lui permettent d’optimiser certaines parties qui ne sont tout simplement pas sécuritaires pour le compilateur C/C++. Lorsque vous avez accès à des pointeurs, de nombreuses optimisations ne sont tout simplement pas sécuritaires.
De plus, Java et C # peuvent effectuer des allocations de tas plus efficacement que C++, car la couche d'abstraction entre le garbage collector et votre code lui permet de faire toute la compression de son tas en même temps (opération assez coûteuse).
Maintenant, je ne peux pas parler pour Java sur ce point, mais je sais que C #, par exemple, supprimera en fait les méthodes et les appels de méthode lorsqu'il sait que le corps de la méthode est vide. Et il utilisera ce type de logique dans votre code.
Comme vous pouvez le constater, de nombreuses raisons expliquent pourquoi certaines implémentations en C # ou Java seront plus rapides.
Ceci étant dit, des optimisations spécifiques peuvent être effectuées en C++ pour éliminer tout ce que vous pouvez faire avec C #, en particulier dans le domaine graphique et à chaque fois que vous êtes proche du matériel. Les pointeurs font des merveilles ici.
Donc, en fonction de ce que vous écrivez, je choisirais l’un ou l’autre. Mais si vous écrivez quelque chose qui ne dépend pas du matériel (pilote, jeu vidéo, etc.), je ne m'inquiéterai pas des performances de C # (encore une fois, je ne peux pas parler de Java). Ça ira très bien.
Un côté Java, @ Swati indique un bon article:
Comme déjà dit dans les articles précédents, JIT peut compiler IL/bytecode en code natif au moment de l'exécution. Le coût de cela a été mentionné, mais pas à sa conclusion:
JIT a un gros problème, c'est qu'il ne peut pas tout compiler: la compilation JIT prend du temps. JIT ne compilera donc que certaines parties du code, alors qu'un compilateur statique produira un fichier binaire natif complet: Pour certains types de programmes, le programme statique Le compilateur surperformera simplement le JIT.
Bien sûr, C # (ou Java, ou VB) est généralement plus rapide à produire une solution viable et robuste que C++ (ne serait-ce que parce que C++ a une sémantique complexe, et la bibliothèque standard C++, bien que intéressante et puissante, est assez médiocre par rapport à la version complète. portée de la bibliothèque standard à partir de .NET ou Java), si bien que la différence entre C++ et .NET ou Java JIT ne sera pas visible par la plupart des utilisateurs, et pour les binaires critiques, eh bien, vous pouvez toujours appeler le traitement C++ à partir de C # ou Java (même si ce type d'appels natifs peut être assez coûteux en soi) ...
Notez qu'en général, vous comparez le code d'exécution C++ avec son équivalent en C # ou en Java. Mais le C++ a une fonctionnalité qui peut surpasser Java/C # telle qu’elle se présente: la métaprogrammation des modèles: le traitement du code est effectué au moment de la compilation (ce qui augmente considérablement le temps de compilation), ce qui aboutit à une exécution nulle (ou presque).
J'ai encore vu un effet réel sur cela (je ne jouais qu'avec des concepts, mais à ce moment-là, la différence était de quelques secondes d'exécution pour JIT, et zéro pour C++), mais cela vaut la peine d'être mentionné, à côté du fait que la métaprogrammation des modèles n'est pas anodine ...
Edit 2011-06-10: En C++, le jeu avec les types se fait lors de la compilation, ce qui signifie produire un code générique appelant du code non générique (par exemple, un analyseur générique de chaîne en type T, appelant une API de bibliothèque standard pour les types qu'il reconnaît, et rendant l'analyseur facilement extensible en son utilisateur) est très facile et très efficace, alors que l’équivalent dans Java ou C # est pénible au mieux à écrire, et sera toujours plus lent et résolu au moment de l’exécution même lorsque les types sont connus au moment de la compilation, ce qui signifie votre seul espérer est pour le JIT pour aligner le tout.
...
Edit 2011-09-20: L'équipe derrière Blitz ++ ( Page d'accueil , Wikipedia ) est allée dans cette direction, et apparemment, son objectif est d'atteindre la performance de FORTRAN en calculs scientifiques en passant le plus possible de l'exécution d'exécution à temps de compilation, via la métaprogrammation du modèle C++. Alors le "J'ai encore vu un effet réel sur cette"partie que j'ai écrit ci-dessus apparemment est-ce que existe dans la vraie vie.
C++ utilise une mémoire différente de Java/C # et présente donc des avantages/inconvénients différents.
Quelle que soit l'optimisation JIT, rien ne sera plus rapide qu'un accès direct à la mémoire par un pointeur (ignorons pour un moment les caches de processeur, etc.). Ainsi, si vous avez des données contiguës en mémoire, y accéder via des pointeurs C++ (c'est-à-dire des pointeurs C ... Donnons sa juste part à Caesar) ira plus vite que sous Java/C #. Et C++ a RAII, ce qui rend beaucoup de traitement beaucoup plus facile qu'en C # ou même en Java. C++ n'a pas besoin de using
pour déterminer l'existence de ses objets. Et C++ n'a pas de clause finally
. Ce n'est pas une erreur.
:-)
Et malgré les structures de type primitive C #, les objets C++ "sur la pile" ne coûteront rien en allocation et en destruction, et aucun GC ne sera nécessaire pour travailler dans un thread indépendant pour effectuer le nettoyage.
En ce qui concerne la fragmentation de la mémoire, les allocateurs de mémoire de 2008 ne sont pas les anciens réservoirs de mémoire de 1980 qui sont généralement comparés à une allocation GC: l'allocation C++ ne peut pas être déplacée en mémoire, mais bien, comme sur un système de fichiers Linux: Qui a besoin d'un disque dur défragmenter quand la fragmentation ne se produit pas? L'utilisation du bon allocateur pour la bonne tâche devrait faire partie de la boîte à outils du développeur C++. Maintenant, écrire des allocateurs n’est pas facile, et la plupart d’entre nous avons mieux à faire, et pour la plupart des applications, RAII ou GC est plus que suffisant.
Edit 2011-10-04: Pour des exemples d’allocateurs efficaces: Sur les plates-formes Windows, depuis Vista, le Low Fragmentation Heap est activé par défaut. Pour les versions précédentes, le LFH peut être activé en appelant la fonction WinAPI HeapSetInformation ). Sur d’autres systèmes d’exploitation, d’autres allocateurs sont fournis (voir https://secure.wikimedia.org/wikipedia/fr/wiki/Malloc pour obtenir une liste)
Maintenant, le modèle de mémoire devient un peu plus compliqué avec l'essor de la technologie multicœur et multithreading. Dans ce domaine, je suppose que .NET a l'avantage et Java, m'a-t-on dit, a tenu bon. Il est facile pour un pirate informatique "sur le métal nu" de louer son code "près de la machine". Mais maintenant, il est bien plus difficile de produire un meilleur assemblage à la main que de laisser le compilateur faire son travail. Pour C++, le compilateur est devenu généralement meilleur que le pirate informatique depuis une décennie. Pour C # et Java, c'est encore plus facile.
Néanmoins, la nouvelle norme C++ 0x imposera aux compilateurs C++ un modèle de mémoire simple, qui normalisera (et simplifiera donc) le code de multitraitement/parallèle/threading efficace en C++, et rendra les optimisations plus simples et plus sûres pour les compilateurs. Mais ensuite, nous verrons dans quelques années si ses promesses sont tenues.
Remarque: Dans cette section, je parle de C++/CLI, c'est-à-dire du C++ hébergé par .NET et non du C++ natif.
La semaine dernière, j'ai suivi une formation sur l'optimisation .NET et découvert que le compilateur statique était très important. Aussi important que JIT.
Le même code compilé en C++/CLI (ou son ancêtre, Managed C++) pourrait être plus rapide que le même code produit en C # (ou VB.NET, dont le compilateur produit le même IL que C #).
Parce que le compilateur statique C++ était bien meilleur pour produire du code déjà optimisé que celui de C #.
Par exemple, l'inlining de fonction dans .NET est limitée aux fonctions dont le bytecode est inférieur ou égal à 32 octets. Ainsi, certains codes en C # produiront un accesseur de 40 octets, qui ne sera jamais inséré par le JIT. Le même code en C++/CLI produira un accesseur de 20 octets, qui sera inséré par le JIT.
Un autre exemple est celui des variables temporaires, qui sont simplement compilées par le compilateur C++ tout en restant mentionnées dans l'IL produite par le compilateur C #. L'optimisation de la compilation statique en C++ donnera moins de code, autorisant ainsi une optimisation plus agressive de JIT.
La raison en était supposée être le fait que le compilateur C++/CLI tirait parti des vastes techniques d'optimisation du compilateur natif C++.
J'aime le C++.
Mais autant que je sache, C # ou Java sont tous un meilleur pari. Non pas parce qu'ils sont plus rapides que le C++, mais parce que, quand on additionne leurs qualités, ils finissent par être plus productifs, nécessitant moins de formation et disposant de bibliothèques standard plus complètes que le C++. Et comme pour la plupart des programmes, leurs différences de vitesse (d'une manière ou d'une autre) seront négligeables ...
Je dispose maintenant de 5 mois de codage professionnel presque exclusif en C # (ce qui s'ajoute à mon CV déjà plein de C++ et de Java et à une touche de C++/CLI).
J'ai joué avec WinForms (Ahem ...) et WCF (cool!), Et WPF (cool !!!! à la fois par XAML et C # brut. WPF est si facile que Swing ne peut pas être comparé) et C # 4.0.
La conclusion est que s'il est plus facile/rapide de produire un code qui fonctionne en C #/Java qu'en C++, il est beaucoup plus difficile de produire un code fort, sûr et robuste en C # (et encore plus en Java) qu'en C++. Les raisons abondent, mais elles peuvent être résumées par:
using
n'est pas aussi facile et puissant, car écrire une implémentation correcte de Dispose est difficile)readonly
et Java final
ne sont nulle part aussi utiles que le const
de C++ (Il n’ya aucun moyen d’exposer des données complexes en lecture seule (un arbre de nœuds, par exemple) en C # sans un travail énorme, alors qu’il s’agit d’une fonctionnalité intégrée à C++. Les données immuables sont une solution intéressante, mais tout ne peut pas être rendu immuable, il ne suffit donc même pas, de loin).Donc, C # reste un langage agréable tant que vous voulez quelque chose qui fonctionne, mais un langage frustrant au moment où vous voulez quelque chose qui toujours et en toute sécurité travaux.
Java est encore plus frustrant, car il a les mêmes problèmes que C #, et plus encore: Manquant l’équivalent du mot clé using
de C #, un de mes collègues très habile a passé trop de temps à s’assurer que ses ressources étaient correctement libérées, alors que l’équivalent en C++ ont été faciles (en utilisant des destructeurs et des pointeurs intelligents).
Je suppose donc que le gain de productivité de C #/Java est visible pour la plupart des codes ... jusqu'au jour où vous avez besoin que le code soit aussi parfait que possible. Ce jour-là, vous saurez souffrir. (vous ne croirez pas ce que nous demandons notre serveur et nos applications graphiques ...).
J'ai gardé le contact avec les équipes de serveurs (j'ai travaillé pendant 2 ans avec elles avant de revenir à l'équipe d'interface graphique), de l'autre côté du bâtiment, et j'ai appris quelque chose d'intéressant.
Ces dernières années, les applications serveur Java avaient tendance à remplacer les anciennes applications serveur C++, car Java disposait de nombreux frameworks/outils et était facile à gérer. déployer, etc. etc ..
… Jusqu'à ce que le problème de la faible latence se pose mal, ces derniers mois. Ensuite, les applications serveur Java, quelle que soit l'optimisation tentée par notre équipe qualifiée Java, ont simplement et proprement perdu la course contre l'ancien serveur C++, pas vraiment optimisé.
Actuellement, la décision est de conserver les serveurs Java pour une utilisation courante, là où les performances restent importantes, ne sont pas concernées par la cible à faible latence et optimisent de manière agressive les applications de serveur C++ déjà plus rapides pour les environnements à faible latence et ultra. Besoins de latence faible.
Rien n'est aussi simple que prévu.
Java, et encore plus C #, sont des langages sympas, avec des bibliothèques et des frameworks standard étendus, où vous pouvez coder rapidement, et aboutissent très bientôt.
Mais lorsque vous avez besoin de puissance brute, d'optimisations puissantes et systématiques, d'un support puissant du compilateur, de puissantes fonctionnalités de langage et d'une sécurité absolue, Java et C # rendent difficile l'obtention des derniers pourcentages manquants mais critiques de qualité dont vous avez besoin pour rester au-dessus la compétition.
C'est comme si vous aviez besoin de moins de temps et de développeurs moins expérimentés en C #/Java qu'en C++ pour produire un code de qualité moyenne, mais en revanche, au moment où vous aviez besoin d'un code d'excellente qualité, il était soudain plus facile et rapide d'obtenir les résultats. droit en C++.
Bien sûr, c’est ma propre perception, peut-être limitée à nos besoins spécifiques.
Néanmoins, c’est ce qui se passe aujourd’hui, aussi bien dans les équipes de l’interface graphique que dans celles du côté serveur.
Bien sûr, je mettrai à jour ce post si quelque chose de nouveau se produit.
"Nous constatons qu'en matière de performances, le C++ l'emporte de loin. Cependant, il a également nécessité les efforts de réglage les plus importants, dont beaucoup ont été effectués à un niveau de sophistication qui ne serait pas disponible pour le programmeur moyen.
[...] La version Java était probablement la plus simple à implémenter, mais la plus difficile à analyser en termes de performances. Plus précisément, les effets autour de la collecte des ordures ménagères étaient compliqués et très difficiles à ajuster. "
Sources:
"Le mot qui va sur Facebook est que 'le code C++ raisonnablement écrit est rapide,'qui souligne les efforts considérables déployés pour optimiser le code PHP et Java. Paradoxalement, le code C++ est plus difficile à écrire que dans d’autres langages, mais un code efficace est beaucoup plus facile [à écrire en C++ que dans d’autres langages]."
- Herb Sutter à // build / , en citant Andrei Alexandresc
Sources:
Chaque fois que je parle de performance gérée ou non gérée, j'aime bien rappeler la série que Rico (et Raymond) ont comparée les versions C++ et C # d'un dictionnaire chinois/anglais. Ceci recherche google vous permettra de lire vous-même, mais j'aime bien le résumé de Rico.
Ai-je honte de ma défaite écrasante? À peine. Le code géré a obtenu un très bon résultat sans effort. Pour vaincre Raymond, il fallait:
- Écrire ses propres fichiers I/O
- Écrire sa propre classe de cordes
- Écrire son propre allocateur
- Écrire sa propre cartographie internationale
Bien sûr, il a utilisé des bibliothèques de niveau inférieur disponibles pour le faire, mais cela demande encore beaucoup de travail. Pouvez-vous appeler ce qui reste d'un programme STL? Je ne pense pas, alors il a conservé la classe std :: vector qui n’a finalement jamais posé problème, ainsi que la fonction de recherche. Presque tout le reste est parti.
Donc, vous pouvez définitivement battre le CLR. Raymond peut faire aller son programme encore plus vite je pense.
Fait intéressant, le temps d'analyse du fichier, tel que rapporté par les minuteries internes des programmes, est à peu près identique: 30 ms pour chacun. La différence est dans les frais généraux.
Pour moi, l'essentiel est qu'il a fallu 6 révisions pour que la version non gérée batte la version gérée qui était un simple port du code non managé d'origine. Si vous avez besoin de toutes les dernières performances (et que vous avez le temps et l'expertise pour l'obtenir), vous devrez vous débrouiller sans gestion, mais pour moi, je vais profiter de l'ordre de grandeur que j'ai sur les premières versions par rapport à la 33 % Je gagne si j'essaye 6 fois.
La compilation pour des optimisations d'UC spécifiques est généralement surestimée. Il suffit de prendre un programme en C++ et de le compiler avec optimisation pour le pentium PRO et de l'exécuter sur un pentium 4. Puis de recompiler avec optim pour le pentium 4. J'ai passé de longs après-midi à le faire avec plusieurs programmes. Résultats généraux ?? Généralement, moins de 2-3% d'augmentation de la performance. Donc, les avantages théoriques de JIT sont presque nuls. La plupart des différences de performances ne peuvent être observées que lorsque vous utilisez des fonctionnalités de traitement de données scalaires, ce qui nécessitera un réglage manuel manuel pour obtenir des performances optimales. Les optimisations de ce type sont lentes et coûteuses à réaliser, ce qui les rend parfois impropres à JIT.
Dans le monde réel et dans les applications réelles, C++ est généralement toujours plus rapide que Java, principalement en raison de l’empreinte mémoire plus faible qui permet d’améliorer les performances du cache.
Mais pour utiliser toutes les fonctionnalités C++, le développeur doit travailler dur. Vous pouvez obtenir des résultats supérieurs, mais vous devez utiliser votre cerveau pour cela. C++ est un langage qui a décidé de vous présenter plus d'outils, en factant le prix que vous devez apprendre pour pouvoir utiliser correctement le langage.
JIT (Compilation Just In Time) peut être incroyablement rapide car il optimise pour la plate-forme cible.
Cela signifie qu'il peut tirer parti de toutes les astuces du compilateur prises en charge par votre processeur, quel que soit le processeur sur lequel le développeur a écrit le code.
Le concept de base du .NET JIT fonctionne comme suit (fortement simplifié):
Appel d'une méthode pour la première fois:
Appel d'une méthode pour la deuxième fois:
Comme vous pouvez le constater, la deuxième fois, son processus est quasiment identique à celui de C++, à l’exception de l’optimisation en temps réel.
Cela dit, il existe encore d’autres problèmes de surcharge qui ralentissent un langage géré, mais le JIT aide beaucoup.
J'aime bien la réponse de Orion Adrian , mais il y a un autre aspect.
La même question a été posée il y a plusieurs décennies à propos du langage de l'Assemblée et des langages "humains" comme le fortran. Et une partie de la réponse est similaire.
Oui, un programme C++ peut être plus rapide que C # avec n’importe quel algorithme (non trivial?), Mais le programme en C # sera souvent aussi rapide ou plus rapide qu’une implémentation "naïve" en C++ et optimisée en C++. Cela prendra plus de temps à développer et pourrait encore battre la version C # avec une très petite marge. Alors, ça vaut vraiment le coup?
Vous devrez répondre à cette question un par un.
Cela dit, je suis un fan de longue date du C++ et je pense que c'est un langage incroyablement expressif et puissant - parfois sous-estimé. Mais dans de nombreux problèmes de la "vraie vie" (pour moi personnellement, cela signifie "le type pour lequel je suis payé pour résoudre"), C # fera le travail plus rapidement et de manière plus sûre.
La plus grande pénalité que vous payez? De nombreux programmes .NET et Java sont des réservoirs de mémoire. J'ai vu des applications .NET et Java prendre "des centaines" de mégaoctets de mémoire, alors que des programmes C++ d'une complexité similaire effleuraient à peine les "dizaines" de MB.
Je ne sais pas combien de fois vous constaterez que le code Java s'exécutera plus rapidement que le C++, même avec Hotspot, mais je vais essayer d'expliquer comment cela pourrait se produire.
Pensez au code Java compilé en tant que langage machine interprété pour la machine virtuelle Java. Lorsque le processeur Hotspot s'aperçoit que certains éléments du code compilé vont être utilisés à plusieurs reprises, il optimise le code machine. Étant donné que l'assemblage manuel est presque toujours plus rapide que le code compilé C++, il est normal de penser que le code machine réglé par programme ne sera pas aussi mauvais.
Ainsi, pour le code hautement répétitif, je pouvais voir où il serait possible pour la machine virtuelle Java Hotspot d’exécuter le Java plus rapidement que le C++ ... jusqu’à ce que le garbage collection entre en jeu. :)
En règle générale, le algorithme de votre programme sera beaucoup plus important pour la rapidité de votre application que le langue. Vous pouvez implémenter un algorithme médiocre dans n’importe quel langage, y compris C++. Dans cet esprit, vous serez généralement en mesure d'écrire du code plus rapidement dans un langage qui vous aidera à implémenter un algorithme plus efficace.
Les langages de niveau supérieur y parviennent très bien en facilitant l’accès à de nombreuses structures de données prédéfinies et efficaces et en encourageant les pratiques qui vous aideront à éviter les codes inefficaces. Bien sûr, ils peuvent parfois aussi faciliter l'écriture d'un tas de code très lent, de sorte que vous devez toujours connaître votre plate-forme.
En outre, C++ rattrape de nouvelles fonctionnalités (notez les guillemets) telles que les conteneurs STL, les pointeurs automatiques, etc. - voir la bibliothèque boost, par exemple. Et vous pouvez parfois trouver que le moyen le plus rapide d'accomplir une tâche nécessite une technique telle que l'arithmétique de pointeur qui est interdite dans un langage de niveau supérieur - bien qu'elles vous permettent généralement d'appeler une bibliothèque écrite dans un langage qui peut l'implémenter à votre guise. .
L'essentiel est de connaître le langage que vous utilisez, son API associée, ce qu'il peut faire et quelles sont ses limitations.
Je ne sais pas non plus ... mes programmes Java sont toujours lents. :-) Je n'ai jamais vraiment remarqué que les programmes C # soient particulièrement lents.
Vous devez définir "performer mieux que ..". Eh bien, je sais, vous avez posé des questions sur la vitesse, mais ce n’est pas tout ce qui compte.
Et ainsi de suite, c'est partial, oui;)
Avec C # et Java, vous payez ce que vous obtenez (codage plus rapide, gestion automatique de la mémoire, grande bibliothèque, etc.). Mais vous n'avez pas beaucoup de place pour marchander sur les détails: prenez le paquet complet ou rien.
Même si ces langages peuvent optimiser une partie du code à exécuter plus rapidement que le code compilé, l’approche globale est inefficace (IMHO). Imaginez que vous conduisez tous les jours à 5 miles de votre lieu de travail, avec un camion! C’est confortable, on se sent bien, on est en sécurité (zone de déformation extrême) et après avoir appuyé sur l’essence pendant un certain temps, ce sera même aussi rapide qu’une voiture standard! Pourquoi n'avons-nous pas tous un camion pour aller au travail? ;)
En C++, vous obtenez ce que vous payez, pas plus, pas moins.
Citant Bjarne Stroustrup: "Le langage C++ est mon langage favori car il génère si peu de déchets" texte du lien
Voici un autre repère intéressant que vous pouvez essayer vous-même sur votre propre ordinateur.
Il compare ASM, VC++, C #, Silverlight, Java applet, Javascript, Flash (AS3)
démo de la vitesse du plugin Roozz
Veuillez noter que la vitesse de javascript varie beaucoup selon le navigateur qui l’exécute. Il en va de même pour Flash et Silverlight car ces plug-ins s'exécutent dans le même processus que le navigateur d'hébergement. Mais le plug-in Roozz exécute des fichiers .exe standard, qui s'exécutent dans leur propre processus. La vitesse n'est donc pas influencée par le navigateur d'hébergement.
Quelques bonnes réponses ici sur la question spécifique que vous avez posée. J'aimerais prendre du recul et regarder la plus grande image.
Gardez à l'esprit que la perception de la vitesse du logiciel que vous écrivez par votre utilisateur est affectée par de nombreux autres facteurs que l'optimisation du codegen. Voici quelques exemples:
La gestion manuelle de la mémoire est difficile à effectuer correctement (pas de fuite) et encore plus difficile à effectuer efficacement (libérez de la mémoire dès que vous en avez terminé). En général, l’utilisation d’un GC est plus susceptible de produire un programme qui gère bien la mémoire. Êtes-vous disposé à travailler très dur et à retarder la livraison de votre logiciel afin de surpasser le GC?
Mon C # est plus facile à lire et à comprendre que mon C++. J'ai également plus de moyens de me convaincre que mon code C # fonctionne correctement. Cela signifie que je peux optimiser mes algorithmes avec moins de risque d'introduire des bogues (et les utilisateurs n'aiment pas les logiciels qui plantent, même s'ils le font rapidement!)
Je peux créer mon logiciel plus rapidement en C # qu'en C++. Cela libère du temps pour travailler sur les performances tout en livrant mon logiciel à temps.
Il est plus facile d'écrire une bonne interface utilisateur en C # qu'en C++, il est donc plus probable que je puisse pousser le travail en arrière-plan pendant que l'interface reste dynamique, ou pour fournir des améliorations ou une interface auditive lorsque le programme doit bloquer pendant un certain temps. Cela ne fait rien plus vite, mais rend les utilisateurs plus heureux d'attendre.
Tout ce que j'ai dit à propos de C # est probablement vrai pour Java, je n'ai simplement pas l'expérience à dire.
Orion Adrian , permettez-moi d'inverser votre post pour voir à quel point vos propos sont sans fondement, car on peut également en dire beaucoup sur le C++. Et dire que le compilateur Java/C # optimise les fonctions vides vous donne vraiment l’impression que vous êtes pas mon expert en optimisation, car a) pourquoi un programme réel devrait-il contenir des fonctions vides, sauf pour le très mauvais code hérité, b) ce n'est vraiment pas l'optimisation noire et optimisée.
Hormis cette phrase, vous vous plaignez de manière flagrante à propos des pointeurs, mais les objets dans Java et C # ne fonctionnent-ils pas comme des pointeurs C++? Ne peuvent-ils pas se chevaucher? Ne peuvent-ils pas être nuls? C (et la plupart des implémentations C++) a le mot-clé restrict, les deux ont des types de valeur, C++ a une référence à une valeur avec une garantie non nulle. Que proposent Java et C #?
En règle générale, C et C++ peuvent être tout aussi rapides ou plus rapides, car le compilateur AOT - un compilateur qui compile votre code avant le déploiement, une fois pour toutes, sur votre serveur de construction central à mémoire vive - peut optimiser le programme compilé en C #. ne peut pas parce qu'il a beaucoup de temps pour le faire. Le compilateur peut déterminer si la machine est Intel ou AMD; Pentium 4, Core Solo ou Core Duo; ou si prend en charge SSE4, etc., et si votre compilateur ne prend pas en charge la répartition à l'exécution, vous pouvez le résoudre vous-même en déployant une poignée de fichiers binaires spécialisés.
Le programme AC # est généralement compilé lors de l’exécution de sorte qu’il fonctionne correctement sur toutes les machines, mais il n’est pas optimisé autant qu’il pourrait l’être pour une configuration unique (processeur, jeu d’instructions, autre matériel) et lui doit passer du temps en premier. Des fonctions telles que la fission de boucle, l’inversion de boucle, la vectorisation automatique, l’optimisation de tout le programme, l’extension du modèle, l’introduction en bourse et bien d’autres sont très difficiles à résoudre, de manière à ne pas gêner l’utilisateur final.
De plus, certaines fonctionnalités du langage permettent au compilateur en C++ ou C de formuler des hypothèses sur votre code qui lui permettent d’optimiser certaines parties qui ne sont tout simplement pas sécuritaires pour le compilateur Java/C #. Lorsque vous n'avez pas accès à l'identifiant de type complet des génériques ou à un flux de programme garanti, de nombreuses optimisations ne sont tout simplement pas sécuritaires.
De plus, C++ et C effectuent plusieurs allocations de pile en même temps avec une seule incrémentation de registre, ce qui est sûrement plus efficace que les allocations Javas et C # en ce qui concerne la couche d'abstraction entre le garbage collector et votre code.
Maintenant, je ne peux pas parler pour Java sur ce point, mais je sais que les compilateurs C++, par exemple, vont effectivement supprimer les méthodes et les appels de méthodes quand il sait que le corps de la méthode est vide, cela éliminera les sous-expressions courantes. , il peut essayer de réessayer pour trouver l’utilisation optimale du registre, il n’impose pas la vérification des limites, il autovectorise les boucles et les boucles internes et est inversé, il déplace les conditionnels hors des boucles, il scinde et divise les boucles. Il étendra std :: vector dans des tableaux à zéro overhead natif, comme vous le feriez avec le mode C. Cela fera des optimisations inter-procédurales. Il construira les valeurs de retour directement sur le site de l'appelant. Il va plier et propager des expressions. Il réorganisera les données de manière conviviale pour le cache. Il fera sauter le filetage. Il vous permet d’écrire des traceurs de rayons de temps de compilation avec un temps d’exécution nul. Cela fera des optimisations très coûteuses basées sur des graphes. Cela réduira la force, s’il remplace certains codes par un code syntaxiquement totalement différent mais sémantiquement équivalent (l’ancien "xor foo, foo" n’est que l’optimisation la plus simple, bien que dépassée, de ce type). Si vous le lui demandez gentiment, vous pouvez omettre les normes à virgule flottante IEEE et activer encore plus d'optimisations telles que la réorganisation des opérandes en virgule flottante. Une fois qu'il a massé et massacré votre code, il peut répéter le processus dans son intégralité, car certaines optimisations jettent souvent les bases de certaines optimisations. Il peut également réessayer avec des paramètres mélangés et voir comment l’autre variante se situe dans son classement interne. Et il utilisera ce type de logique dans votre code.
Comme vous pouvez le constater, il existe de nombreuses raisons pour lesquelles certaines implémentations C++ ou C seront plus rapides.
Ceci étant dit, de nombreuses optimisations peuvent être apportées en C++ pour éliminer tout ce que vous pouvez faire avec C #, en particulier dans les domaines du calcul numérique, du temps réel et du monde proche du métal, mais pas exclusivement. Vous n'avez même pas besoin de toucher un seul pointeur pour parcourir un long chemin.
Donc, en fonction de ce que vous écrivez, je choisirais l’un ou l’autre. Mais si vous écrivez quelque chose qui ne dépend pas du matériel (pilote, jeu vidéo, etc.), je ne m'inquiéterai pas des performances de C # (encore une fois, je ne peux pas parler de Java). Ça ira très bien.
Généralement, certains arguments généralisés peuvent sembler sympas dans des publications spécifiques, mais ne paraissent en général pas crédibles.
Quoi qu'il en soit, pour faire la paix: AOT est génial, tout comme JIT . La seule réponse correcte peut être: ça dépend. Et les personnes intelligentes savent que vous pouvez utiliser le meilleur des deux mondes de toute façon.
Si vous êtes un programmeur Java/C # qui apprend le C++, vous serez tenté de continuer à penser en termes de Java/C # et de traduire textuellement la syntaxe C++. Dans ce cas, vous n'obtenez que les avantages mentionnés précédemment du code natif par rapport à interprétés/JIT. Pour obtenir les gains de performances les plus importants en C++ par rapport à Java/C #, vous devez apprendre à penser en C++ et à concevoir du code spécifiquement pour exploiter les atouts de C++.
Pour paraphraser Edsger Dijkstra : [votre langue maternelle] mutile l'esprit au-delà de la récupération.
Pour paraphraser Jeff Atwood : vous pouvez écrire [votre langue maternelle] dans n’importe quelle nouvelle langue.
L'une des optimisations les plus significatives de JIT est l'intégration de méthodes. Java peut même intégrer des méthodes virtuelles s'il peut garantir l'exactitude de l'exécution. Ce type d’optimisation ne peut généralement pas être effectué par des compilateurs statiques standard car il nécessite une analyse complète du programme, ce qui est difficile en raison d’une compilation séparée (en revanche, JIT dispose de tous les programmes disponibles). La méthode inlining améliore les autres optimisations en donnant des blocs de code plus importants à optimiser.
L'allocation de mémoire standard en Java/C # est également plus rapide et la désallocation (GC) n'est pas beaucoup plus lente, mais seulement moins déterministe.
Le code exécutable produit à partir d'un compilateur Java ou C # n'est pas interprété - il est compilé en code natif "juste à temps" (JIT). Ainsi, lors de l’exécution, le premier code temps dans un programme Java/C # est rencontré, car le "compilateur runtime" (compilateur JIT) transforme le code octet (Java) ou le code IL (C #) en instructions machine natives. Cependant, la prochaine fois que ce code est rencontré alors que l'application est toujours en cours d'exécution, le code natif est exécuté immédiatement. Ceci explique comment certains programmes Java/C # semblent être lents au départ, mais fonctionnent mieux à mesure qu'ils durent longtemps. Un bon exemple est un site Web ASP.Net. La première fois que vous accédez au site Web, cela risque d’être un peu plus lent car le code C # est compilé en code natif par le compilateur JIT. Les accès ultérieurs se traduisent par un site Web beaucoup plus rapide, mis à part la mise en cache côté serveur et côté client.
Il est peu probable que les langages de machine virtuelle surpassent les langages compilés, mais ils peuvent s’approcher suffisamment pour que cela n’importe pas, pour (au moins) les raisons suivantes (je parle pour Java ici car je n’ai jamais fait C #).
1/Le Java Runtime Environment est généralement capable de détecter les morceaux de code fréquemment exécutés et de compiler juste-à-temps (JIT) de ces sections afin qu’à l’avenir elles soient exécutées intégralement. la vitesse.
2/De nombreuses parties des bibliothèques Java sont compilées de sorte que, lorsque vous appelez une fonction de bibliothèque, vous exécutiez un code compilé, non interprété. Vous pouvez voir le code (en C) en téléchargeant OpenJDK.
3/Sauf si vous effectuez des calculs volumineux, votre programme est en grande partie en attente d'attendre les informations d'un humain très lent (relativement parlant).
4/Etant donné qu'une grande partie de la validation du Java bytecode est effectuée au moment du chargement de la classe, la charge de travail normale des contrôles à l'exécution est considérablement réduite.
5/Dans le pire des cas, le code à forte performance peut être extrait dans un module compilé et appelé depuis Java (voir JNI) afin d’être exécuté à la vitesse maximale.
En résumé, le bytecode Java ne sera jamais plus performant que le langage machine natif, mais il existe des moyens de remédier à ce problème. Le gros avantage de Java (à mon avis) est la bibliothèque standard HUGE et la nature multiplate-forme.
En réalité, C # ne s’exécute pas vraiment sur une machine virtuelle, contrairement à Java. IL est compilé en langage Assembly, qui est entièrement du code natif et s'exécute à la même vitesse que le code natif. Vous pouvez pré-JIT une application .NET qui supprime entièrement le coût JIT et vous exécutez alors du code entièrement natif.
Le ralentissement avec .NET ne viendra pas parce que le code .NET est plus lent, mais parce qu’il fait beaucoup plus dans les coulisses pour faire des choses telles que le ramassage des ordures, vérifier les références, stocker des cadres de pile complets, etc. Cela peut être assez puissant et utile lorsque applications de construction, mais a également un coût. Notez que vous pouvez également faire toutes ces choses dans un programme C++ (une grande partie de la fonctionnalité .NET principale est en réalité un code .NET que vous pouvez visualiser dans ROTOR). Toutefois, si vous écriviez à la main les mêmes fonctionnalités, vous obtiendrez probablement un programme beaucoup plus lent, car le runtime .NET a été optimisé et optimisé.
Cela dit, l’un des points forts du code géré est qu’il peut être entièrement vérifiable, c’est-à-dire. vous pouvez vérifier que le code n'aura jamais accès à la mémoire d'un autre processus ou faire des choses vides de mémoire avant de l'exécuter. Microsoft possède un prototype de système d'exploitation entièrement géré qui a démontré de manière surprenante qu'un environnement géré à 100% peut fonctionner beaucoup plus rapidement que tout système d'exploitation moderne en tirant parti de cette vérification pour désactiver les fonctionnalités de sécurité qui ne sont plus nécessaires aux programmes gérés. (nous parlons comme 10x dans certains cas). La radio de SE a un grand épisode parlant de ce projet.
Cela ne se produirait que si l'interprète Java génère un code machine réellement meilleur optimisé que le code machine généré par votre compilateur pour le code C++ que vous écrivez, au point où le code C++ est plus lent que le Java et le coût d'interprétation.
Cependant, les chances que cela se produise sont plutôt faibles - à moins que peut-être Java ne possède une bibliothèque très bien écrite et que vous ayez votre propre bibliothèque C++ mal écrite.
En réalité, la machine virtuelle Java HotSpot de Sun utilise une exécution en "mode mixte". Il interprète le bytecode de la méthode jusqu'à ce qu'il détermine (généralement via un compteur) qu'un bloc de code particulier (méthode, boucle, bloc try-catch, etc.) va être exécuté souvent, puis il est compilé par JIT. Le temps requis pour compiler une méthode JIT prend souvent plus de temps que si la méthode devait être interprétée s'il s'agit d'une méthode rarement exécutée. Les performances sont généralement plus élevées en "mode mixte", car la JVM ne perd pas de temps en code JIT qui est rarement, voire jamais, exécuté. C # et .NET ne le font pas. .NET JITs tout ce qui, souvent, gaspille du temps.
Vous pouvez obtenir de courtes rafales lorsque Java ou que CLR est plus rapide que C++, mais dans l'ensemble, les performances sont moins bonnes pour la vie de l'application: voir www.codeproject.com/KB/dotnet/RuntimePerformance.aspx pour certains résultats. pour ça.
Voici la réponse de Cliff Click: http://www.azulsystems.com/blog/cliff/2009-09-06-Java-vs-c-performanceagain
Consultez le document Dynamo de HP Labs, un interpréteur pour le PA-8000 qui s'exécute sur le PA-8000 et exécute souvent des programmes plus rapidement que nativement. Alors cela ne semblera pas du tout surprenant!
Ne considérez pas cela comme une "étape intermédiaire" - l'exécution d'un programme implique déjà de nombreuses autres étapes, dans n'importe quelle langue.
Cela revient souvent à:
les programmes ont des points chauds. Ainsi, même si vous exécutez plus lentement 95% du corps du code que vous avez à exécuter, vous pouvez toujours rester compétitif en termes de performances si vous êtes plus rapide au top 5%
un HLL en sait plus sur votre intention qu'un LLL comme C/C++, et peut donc générer un code plus optimisé (OCaml en a encore plus, et en pratique est souvent encore plus rapide)
un compilateur JIT a beaucoup d'informations qu'un compilateur statique n'a pas (comme, les données réelles que vous avez cette fois)
un compilateur JIT peut effectuer des optimisations au moment de l'exécution que les lieurs traditionnels ne sont pas vraiment autorisés à le faire (comme réorganiser des branches de manière à ce que la casse soit commune ou mettre en ligne des appels de bibliothèque)
Dans l’ensemble, le C/C++ est un langage assez moche en termes de performances: il existe relativement peu d’informations sur vos types de données, aucune information sur vos données et aucune exécution dynamique permettant une optimisation importante de l’exécution.
Si j'ai bien compris, C/C++ produit du code natif à exécuter sur une architecture de machine particulière. Inversement, des langages comme Java et C # s'exécutent sur une machine virtuelle, ce qui éloigne l'architecture native. Logiquement, il semblerait impossible que Java ou C # corresponde à la vitesse du C++ à cause de cette étape intermédiaire. Cependant, on m'a dit que les derniers compilateurs ("points chauds") peuvent atteindre cette vitesse, voire dépasser. il.
C'est illogique. L'utilisation d'une représentation intermédiaire ne dégrade pas les performances de manière inhérente. Par exemple, llvm-gcc compile C et C++ via LLVM IR (une machine virtuelle à registre infini) en code natif et réalise d’excellentes performances (souvent supérieures à GCC).
C’est peut-être plus une question de compilateur que de question de langue, mais est-ce que quelqu'un peut expliquer en anglais simple comment il est possible pour l’une de ces langues de machine virtuelle d’être plus performante qu’une langue maternelle?
Voici quelques exemples:
Les machines virtuelles avec la compilation JIT facilitent la génération de code au moment de l’exécution (par exemple, System.Reflection.Emit
sur .NET) afin que vous puissiez compiler le code généré à la volée dans des langages tels que C # et F #, mais que vous deviez écrire un interprète relativement lent. C ou C++. Par exemple, pour implémenter des expressions régulières.
Des parties de la machine virtuelle (la barrière d'écriture et l'allocateur, par exemple) sont souvent écrites dans un assembleur codé à la main, car C et C++ ne génèrent pas assez de code. Si un programme insiste sur ces parties d'un système, il pourrait éventuellement surpasser tout ce qui peut être écrit en C ou C++.
La liaison dynamique du code natif nécessite la conformité à une ABI pouvant nuire aux performances et empêcher l'optimisation de l'ensemble du programme, tandis que la liaison est généralement différée sur les ordinateurs virtuels et peut tirer parti d'optimisations de l'ensemble du programme (comme les génériques réifiés de .NET).
Je voudrais également aborder quelques problèmes avec la réponse hautement votée de paercebal ci-dessus (car quelqu'un supprime continuellement mes commentaires sur sa réponse) qui présente un point de vue contre-productif:
Le traitement du code se fera lors de la compilation ...
Par conséquent, la métaprogrammation des modèles ne fonctionne que si le programme est disponible au moment de la compilation, ce qui n’est souvent pas le cas, par exemple. Il est impossible d'écrire une bibliothèque d'expressions régulières aux performances concurrentielles dans Vanilla C++ car elle est incapable de générer du code à l'exécution (un aspect important de la métaprogrammation).
... jouer avec les types est fait au moment de la compilation ... l'équivalent dans Java ou C # est pénible au mieux à écrire, et sera toujours plus lent et résolu au moment de l'exécution même lorsque les types sont connus à la compilation temps.
En C #, cela n'est vrai que pour les types de référence et pas pour les types de valeur.
Quelle que soit l'optimisation JIT, rien ne sera plus rapide que l'accès pointeur direct à la mémoire ... si vous avez des données contiguës en mémoire, y accéder via des pointeurs C++ (c'est-à-dire des pointeurs C ... Donnons sa juste part à César) ira plus vite qu'en Java/C #.
Les gens ont observé Java bat C++ sur le test SOR du test SciMark2 précisément parce que les pointeurs entravent les optimisations liées aux alias.
Il convient également de noter que .NET fait la spécialisation des types de génériques dans les bibliothèques liées dynamiquement après la liaison, alors que C++ ne le peut pas, car les modèles doivent être résolus avant la liaison. Et évidemment, le gros avantage des génériques par rapport aux modèles est la compréhension des messages d'erreur.
Dans certains cas, le code géré peut en réalité être plus rapide que le code natif. Par exemple, les algorithmes de récupération de place "balayer et balayer" permettent à des environnements tels que JRE ou CLR de libérer un grand nombre d'objets de courte durée (généralement) en une seule passe, la plupart des objets de segment de mémoire C/C++ étant libérés un à un. une fois.
De wikipedia :
Dans de nombreux cas pratiques, les algorithmes gourmands en allocation/désallocation implémentés dans des langages collectés peuvent être plus rapides que leurs équivalents utilisant une allocation de tas manuelle. Une des principales raisons à cela est que le ramasse-miettes permet au système d'exécution d'amortir les opérations d'allocation et de désallocation de manière potentiellement avantageuse.
Cela dit, j'ai écrit beaucoup de C # et beaucoup de C++ et j'ai exécuté beaucoup de tests. Selon mon expérience, C++ est beaucoup plus rapide que C #, de deux manières: (1) si vous prenez du code que vous avez écrit en C #, portez-le en C++, le code natif tend pour être plus rapide. Combien plus vite? Cela varie énormément, mais il n'est pas rare de constater une amélioration de la vitesse de 100%. (2) Dans certains cas, le garbage collection peut massivement ralentir une application gérée. Le .NET CLR fait un travail épouvantable avec de grands tas (disons,> 2 Go) et peut finir par passer beaucoup de temps en GC, même dans des applications qui ont peu, voire pas d'objets de durée de vie moyenne.
Bien sûr, dans la plupart des cas que j'ai rencontrés, les langages gérés sont assez rapides, et le compromis entre maintenance et codage pour les performances supplémentaires du C++ n'est tout simplement pas bon.
Pour tout ce qui nécessite beaucoup de vitesse, la machine virtuelle Java appelle simplement une implémentation C++. Il est donc plus question de la qualité de leurs bibliothèques que de celle de la machine virtuelle pour la plupart des tâches liées aux systèmes d’exploitation. Le ramassage des ordures réduit de moitié la mémoire, mais l’utilisation des fonctionnalités les plus sophistiquées de STL et de Boost aura le même effet, mais avec de nombreuses fois le potentiel de bug.
Si vous utilisez uniquement des bibliothèques C++ et de nombreuses fonctionnalités de haut niveau dans un projet volumineux comportant de nombreuses classes, vous vous retrouverez probablement plus lentement que d'utiliser une machine virtuelle. Sauf beaucoup plus sujet aux erreurs.
Cependant, l’avantage du C++ est qu’il vous permet de vous optimiser, sinon vous êtes coincé avec ce que fait le compilateur/jvm. Si vous créez vos propres conteneurs, écrivez votre propre gestion de mémoire alignée, utilisez SIMD et passez à Assembly ici et là, vous pouvez accélérer au moins 2x à 4x plus que ce que la plupart des compilateurs C++ feront par eux-mêmes. Pour certaines opérations, 16x-32x. En utilisant les mêmes algorithmes, si vous utilisez de meilleurs algorithmes et que vous parallélisez, les augmentations peuvent être spectaculaires, parfois des milliers de fois plus rapidement que les méthodes couramment utilisées.
Je ne pense pas que les performances doivent être prises en compte en ce qui concerne la vitesse de traitement du serveur ces jours-ci (après que tous les processeurs multicœur soient sur le marché). Il devrait être plus défini en fonction de l'utilisation de la mémoire. Et de cette façon, Java a un léger inconvénient.
Cependant, toutes les langues de programmation conviennent à des fins différentes. Et c’est leur domaine de compétition, à chaque section ce sont des gagnants différents.
Et je suis sûr que Java gagnera à long terme car il poursuit son développement et sa compétitivité dans toutes ses nouvelles fonctionnalités.
J'ai trouvé un lien ici qui corrobore ma raison de voter pour Java
Une réponse très courte: avec un budget fixe, vous obtiendrez une application Java plus performante qu'une application C++ (considérations en matière de retour sur investissement). De plus, la plate-forme Java dispose de profils plus convenables vos hotspots plus rapidement
Je le regarde à partir de quelques points différents.
En plus de ce que d'autres ont dit, si je comprends bien, .NET et Java ont une meilleure capacité d'allocation de mémoire. Par exemple. ils peuvent compacter la mémoire car elle est fragmentée alors que C++ ne le peut pas (en mode natif, mais cela est possible si vous utilisez un ramasse-miettes intelligent).