108 votes

C# versus performance C++

J'ai souvent entendu dire que les gens préfèrent C++, C#, principalement dans l'exécution de code critique,parce que le GC peut tourner sur le chemin critique, provoquant l'exécution de la peine.

Cependant, quand j'ai lu le C++, j'ai réalisé que C++ offre la smart pointeur de fonctions dans lequel le programmeur n'a pas besoin de s'inquiéter à propos de la gestion de la mémoire. Par exemple, le shared_ptr avec comptage de référence sera de gérer la mémoire pour nous. Par conséquent,nous n'avons pas vraiment se soucier de la durée de vie d'un objet et quand il être supprimé. Ne serait-ce pas similaire à C# GC et le destructeur de l'objet serait appelé à l'exécution de code critique?

Aussi, une autre question est de savoir si nous n'avions pas utiliser smart pointeur en C++ et nous venons de recourir à pointeur brut, nous avons toujours besoin d'appeler delete pour effacer la mémoire de masse. Donc, à partir de ma compréhension, chaque objet créé par le C++ ou C# serait encore être détruite, mais la différence n'est qu'à nous de gérer la mémoire nous-mêmes dans le C++, mais en C#, nous laissons le gouvernement pour gérer. Alors, quel est l'effet NET de il lorsque l'on compare C++ et C#, puisque les deux objets doivent encore être supprimés?

288voto

Jon Harrop Points 26951

J'ai souvent entendu dire que les gens préfèrent C++, C#, principalement dans l'exécution de code critique,parce que le GC peut tourner sur le chemin critique, provoquant l'exécution de la peine.

J'ai entendu dire que dans certains cercles, mais jamais respectable cercles.

Par exemple, j'ai consulté pour une entreprise à Londres, qui ont été la vente de la bourse de logiciel qui a été écrit dans 1 000 000 lignes de C++. Plus de 40 développeurs a travaillé pendant près de 15 ans et qu'ils étaient convaincus que le C++ était la bonne solution pour de tels logiciels en raison de la latence et le débit de la performance ont été à la fois critique. Ils ont été la réalisation de latences aussi bas que 50 ms (avec un seul opérateur connecté!) et le débit aussi élevé que 10k transactions par seconde (tps). Cependant, ils avaient de la difficulté à l'appui de plus de 2 000 commerçants parce qu'ils avaient plusieurs threads par l'opérateur (pas de async) et, en fait, les commerçants ont été les rapports des latences de six secondes parce que le temps de latence de leur code C++ augmenté de façon exponentielle avec le nombre de commerçants. J'ai réécrit leur code dans les 3 mois à l'aide de F#.NET et atteint les latences aussi faibles que 0,1 ms et des débits de plus de 200ktps en utilisant seulement de 6 000 lignes de F#. Ma solution a été entièrement asynchrone (pris en charge plus de 10 000 simultanée trader connexions) et à tolérance de pannes.

Maintenant, je ne dis pas que C++ n'a pas pu servir à atteindre des performances encore meilleures que les miennes. Au contraire, je suis sûr qu'il aurait pu atteindre de meilleures performances, mais je crois aussi qu'il aurait prises par l'homme depuis des décennies par de véritables experts et a coûté des millions de livres. Après tout, il ya une raison pourquoi la Bourse de Londres a payé £18m pour Millenium et leur faible temps de latence C++ solution. Toutefois, je crois que la grande majorité des gens qui prématurément optimiser loin de collecte des ordures ne savent pas de quoi ils parlent et ne serait pas capable de construire une bonne solution dans n'importe quelle langue. Ces gens en général ne savent C++ et n'ont aucune connaissance de la collecte des ordures algorithmes, ce qui est effrayant parce que les programmeurs en C++ réinventer GC algorithmes de chaque jour. Un bon test est de leur demander comment la collecte des ordures œuvres. Si ils décrivent naïf mark-sweep circa 1960 alors qu'ils n'ont pas fait leurs devoirs.

D'autre part, certaines personnes écrivent excellente à faible latence et à haut débit de code dans les ordures collectées langues. Voir, par exemple, la LMAX Perturbateur (Java) et Plus Rapide FIX moteur (C#). Alors, les gens ont écrit à faible latence logiciel en Java et C# et, par conséquent, il est clairement possible. En particulier, l'utilisation de tableaux de types de valeur est connue, mais sous-estimé solution à faible latence de la programmation .NET.

Cependant, quand j'ai lu le C++, j'ai réalisé que C++ offre la smart pointeur de fonctions dans lequel le programmeur n'a pas besoin de s'inquiéter à propos de la gestion de la mémoire. Par exemple, le shared_ptr avec comptage de référence sera de gérer la mémoire pour nous. Par conséquent,nous n'avons pas vraiment se soucier de la durée de vie d'un objet et quand il être supprimé. Ne serait-ce pas similaire à C# GC et le destructeur de l'objet serait appelé à l'exécution de code critique?

Oui. Les programmeurs en C++ se plaignent souvent de traçage des ramasseurs d'ordures non-déterministe et causant des pauses. Thread-safe shared_ptr en C++ est non-déterministe, car les threads course à décrémenter le décompte à zéro et le vainqueur de la condition de la course est chargé de l'appel du destructeur. Et shared_ptr causes des pauses lorsque décrémente avalanche, par exemple, lorsqu'un thread libère la dernière référence à un arbre, le thread est suspendu pour une surabondance de la longueur de temps alors que chaque destructeur dans l'arbre est appelé. Comptage de référence peut être faite différentiels mise en file d'attente des destructeurs, mais qui récupère le non-déterminisme de traçage de collecte des ordures. Enfin, le comptage de références avec le shared_ptr est plusieurs fois plus lent que le traçage de la collecte des ordures , car l'incrémentation et la décrémentation de compte, le cache est hostile.

Sur une note connexe, les programmeurs en C++ souvent à tort de prétendre qu' shared_ptr collecte des ordures le plus tôt possible dans le programme et, par conséquent, la collecte de données plus "rapidement" à un traçage garbage collector peut. En fait, la portée de la fonction de comptage de référence comme shared_ptr garde des déchets flottants jusqu'à ce qu'il tombe hors de la portée qui augmente le registre de la pression peut même augmenter la consommation de mémoire par rapport au suivi de collecte des ordures.

Donc, shared_ptr est en effet rien de plus qu'un pauvre homme du garbage collector. Après tout, les vieilles machines virtuelles et CLRs à la fois servir de comptage de référence à un certain moment dans l'histoire, et à la fois il est passé en faveur de meilleures formes de collecte des ordures. Comptage de référence est seulement populaire en C++, car il n'est pas facile de marcher sur la pile et de la redirection de pointeurs de manière précise le traçage de la collection est extrêmement difficile.

Aussi, une autre question est de savoir si nous n'avions pas utiliser smart pointeur en C++ et nous venons de recourir à pointeur brut, nous avons toujours besoin d'appeler delete pour effacer la mémoire de masse. Donc, à partir de ma compréhension, chaque objet créé par le C++ ou C# serait encore être détruite, mais la différence n'est qu'à nous de gérer la mémoire nous-mêmes dans le C++, mais en C#, nous laissons le gouvernement pour gérer. Alors, quel est l'effet NET de il lorsque l'on compare C++ et C#, puisque les deux objets doivent encore être supprimés?

Dans sa forme la plus simple, la répartition en C++ se résume à un appel général à usage partagé (globale) de l'allocateur de mémoire comme malloc et en C#, ça revient à pointeur de la bosse de l'allocation dans un thread locaux de la pépinière génération (gen0). Par conséquent, ordinaire attribution en C# est beaucoup plus rapide qu'à l'ordinaire attribution en C++. Cependant, déforme un vrai logiciel. Dans la pratique, les programmeurs en C++ éviter d'appeler le grand objectif global de l'allocation en faveur de l'utilisation de thread-local piscine allocateurs chaque fois que possible. D'autre part, les développeurs C# s'appuyer sur l'objectif général de gestion de la mémoire fournies par la solution .NET car elle simplifie grandement les Api (mémoire de la propriété a été rendue abstraite) et est plus que rapide dans la grande majorité des cas. Dans les rares cas où la solution la plus simple n'est pas suffisante, le développeur C# gouttes pour abaisser le niveau de code C# et écrit un pool d'allocation de l'aide d'un tableau de types de valeur.

Alors je serais probablement juste de faire deux observations:

  • Précis de traçage de la collecte des ordures est extrêmement utile, en général, et est livré avec C# et trop difficile avec le C++.

  • Gestion de la mémoire bits astuces (par exemple, la contrebande de bits dans les pointeurs) sont parfois possible en C++, mais interdit en C#.

Donc, il n'est pas facile de comparer, C++ et C# assez dans ce contexte.

En outre, la gestion de la mémoire est sans doute pas le plus grand souci de performances, de toute façon. De nombreuses autres questions peuvent avoir un effet significatif de la qualité du code généré sur obscur architectures (où les compilateurs C sont généralement beaucoup plus mature) vs JIT compiler pour un CPU, la vectorisation comme SIMD (.NET ne peu), compilé par JIT de l'exécution du code généré (comme les expressions régulières .NET) vs un interprète en C++ et de la compilation des Gpu ou Fpga.

Je pense que le seul bon conseil que je puisse vous donner est la suivante: faire vos propres recherches et de ne pas écouter les masses incultes.

125voto

John Dibling Points 56814

Cette question et ma réponse originale à cette question ont d'abord été écrit près de trois ans. Depuis ce temps, j'ai été surpris de recevoir un plus ou moins constant flux de voix, à la fois en haut et en bas, même jusqu'à aujourd'hui. Je pensais que maintenant serait un bon moment pour revoir cette réponse. Je vais laisser l'original vers le bas ci-dessous à titre de référence.


La question de la langue qui est la plus rapide est maintenant largement discutable. Ils peuvent à la fois me fait pour être extrêmement rapide. Le même était vrai il y a trois ans, mais ma réponse a été délibérément n'est pas centrée sur une étude technique des deux langues et la façon dont leurs différences d'incidence sur les performances. Mon accent était mis sur les personnes qui utilisent ces langues, et la ligne de fond est:est-ce

Le facteur le plus important dans la détermination de la vitesse et de l'efficacité du programme n'est pas le langage utilisé pour programmer, mais les gens derrière les claviers.

Dans sa réponse, @Jon Harrop explique le succès qu'il avait re la mise en œuvre d'un système d'héritage dans un GC ed .NET de la langue. Je n'ai pas de litige ou de doute de son expertise en la matière. J'ai, Comme lui, je suis aussi employées dans les services financiers de l'arène et ont été pour aller sur 20 ans. Pendant ce temps, j'ai vu beaucoup de systèmes différents-allant de la qualité de fantastique horribles. Je suis une C++ guy -- c'est ce que je fais pour vivre. Je sais aussi F#, C#, VB, Ruby, Perl, assembleur et probablement 30 autres langues. Mais mon expertise dans ces langues ne sont pas de mes compétences en C++. Si je devais écrire ce que Jon a écrit en F#, son code écraser le mien, pas de doute dans mon esprit.

Est-ce à dire F# est plus rapide que le C++? Pas de. Ce que cela signifie, c'est la personne derrière le F# du clavier (Jon) est mieux que moi. Je n'ai aucun doute à ce sujet.

Dans le trading à haute fréquence (mon secteur d'activité), la vitesse est roi. On mesure la latence dans ces courts intervalles que la vitesse à laquelle un signal électrique qui se déplace sur un câble réseau est une partie de l'équation. Il y a un certain nombre de centres de données où c'est considéré comme si important qu'ils aient des bobines de câble supplémentaire d'aller à chaque cage de sorte que chaque ordinateur du contrôleur de domaine a la même longueur connectés, afin d'éliminer tout avantage de la proximité dans le centre de données. Chaque composant et de la ligne de questions de code. Dans un environnement comme celui-ci, même de 1 milli c'est une éternité. Vous pourriez aussi bien aller pour le déjeuner. A titre indicatif, nos normes en matière de rendement est de 10 micros à partir du moment où un message vient de l'échange à la fois, il a été entièrement transformé et le client message envoyé sur le message sortant du bus. 10 micros est juste le plafond absolu de performance acceptable. La moyenne est plus proche de 2 à 5 micros. Cela inclut tous les calculs, la valeur ajoute de la base de données et mises à jour. Et nos systèmes sont écrits en 100% C++.

Est-ce à dire C++ est plus rapide que F#? Pas de. Ce que cela signifie, c'est que nos systèmes sont un produit mûr qui a été développé par des experts dans le domaine (à grands frais) sur plusieurs années. Comme la technologie évolue, notre code de changements pour obtenir de nouveaux avantages. Bien que notre produit est parmi les meilleurs dans l'industrie, d'autres produits concurrents écrits dans d'autres langues ont des performances similaires. Ce n'est pas la langue qui compte le plus, c'est le peuple en l'utilisant. Si j'étais aussi bon en C# F# que je suis sur le C++, j'aimerais être écrit en C# et F#.


Originale dans ma réponse ci-dessous, j'ai essayé de me concentrer sur les différences entre les programmeurs qui utilisent une langue, plutôt que la langue elle-même. L'important n'est pas la langue, mais les gens, leur expertise, les questions qu'ils posent, et leur expérience. Ce n'est pas la meilleure réponse que j'ai jamais donné, mais il a attiré beaucoup d'attention. Ce n'est pas exactement ce que j'allais écrire aujourd'hui, mais je vais laisser reposer inédite de référence.


Je suis sûr que cela va obtenir downvoted une centaine de fois, mais j'ai juste à dire:

Alors, quel est l'effet NET de il lorsque l'on compare C++ et C#, puisque les deux objets doivent encore être supprimés?

De mon point de vue (et c'est un admis coup de gueule) l'effet net est que certains (beaucoup?) C#, programmeurs ne comprends pas vraiment ce que leurs programmes, et de sorte que leur logiciel n'est pas très bon.

L'attitude/la croyance que:

nous n'avons pas vraiment se soucier de la durée de vie d'un objet et quand il l'ont supprimé

...semble imprégner le C#/Java/VB/[insérer "facile" de la langue ici] la culture. Je suis allé une fois à une MS-parrainé présentation de Chicago, où Don Box a parlé de la nouvelle .NET des langues et de la plateforme. À un moment, il s'est adressé à toutes les personnes dans le public qui ont été "malade et fatigué de le C++ les gars jubilation" à quelle vitesse C++ a été comparée à celle d'autres langues de l'époque. "Maintenant, je vais vous le prouver une fois pour toutes qu'ils sont mauvais," dit-il. Alors procédé pour créer 2 programmes. Dans le programme C#, il a créé une boucle qui instancié 10 millions de chaînes, et il a mis un point d'arrêt juste après la boucle. Dans la version C++, il a alloué et libéré le même nombre de chaînes à l'aide d' new et delete et définir un point d'arrêt à l'accolade de fermeture pour main. A couru le programme. la version C# du point d'arrêt frappé beaucoup plus tôt que la version C++, et la foule était en délire.

Les moutons dans cette foule n'a pas pris la peine de se demander pourquoi la version C# a été plus rapide, si oui ou non les 2 programmes vraiment fait la même chose, ou de demander à voir l'onglet Performances du Gestionnaire des Tâches. J'ai demandé à le voir. Ne ne serait pas me laisser, et "accusé" d'être un C++ mec. Rapidement fermé deux de ses programmes et déplacé dans le sujet suivant.

Le GC ed langues vous protéger de ce qui se passe réellement dans votre machine. Pour écrire un programme de fonctionnement, vous n'avez pas vraiment besoin de connaître la différence entre les pointeurs en C++ et la collecte des ordures en C#. C'est comme la formation d'un mécanicien de voiture seulement comment utiliser le plug-in outils de diagnostic, mais pas de lui enseigner comment un moteur à combustion interne en fait des œuvres.

Ainsi, le résultat net? Demandez-moi et je vais vous dire les programmes ne sont pas aussi bon.

Je blâme le système universitaire autant que rien d'autre, mais c'est une histoire pour un autre jour.

OK, coup de gueule. Laisser le feu de commencer.

66voto

Nikolai N Fetissov Points 52093

La différence est que dans C++, vous pouvez choisir quand à détruire les objets.

46voto

James McNellis Points 193607

Ce peut être un peu hors-sujet; comme d'autres l'ont souligné, la performance est relative et vous pouvez écrire mal l'exécution de code à indépendamment de si vous avez la collecte des ordures. Comme John Dibling j'attends de ce post ne peut pas être bien pris par certains.

  • Écrits en C++, les ressources des durées de vie sont gérées de façon déterministe, de manière uniforme, et automatiquement.

  • Dans la plupart des langues avec la collecte des ordures (C# et Java en particulier), les ressources des durées de vie sont gérées nondeterministically, valeurs, et seulement en partie automatiquement.

Le problème avec la collecte des ordures (implémenté en Java et C#) n'est pas vraiment qu'il gère la mémoire pour vous. Qui, en soi, une fonctionnalité intéressante. Il a certainement des avantages.

Le problème est que vous vous êtes laissé dehors dans le froid avec tous les non-mémoire de ressources. Si vous avez un fichier poignée, douille, clé de registre, natif de la synchronisation de l'objet, ou de toute autre ressource qui nécessite le nettoyage déterministe, vous avez à faire un travail supplémentaire pour s'assurer qu'ils sont nettoyés correctement.

Oui, il y a des facilités linguistiques qui sont là pour vous aider avec ceci (C# a IDisposable, using, et finally, par exemple), mais le fardeau tombe toujours sur vous, le programmeur, à écrire du code pour gérer manuellement la durée de vie de la ressource.

En C++, toutes les ressources sont gérées de la même façon en utilisant le Champ d'application Lié à la Gestion des Ressources (SBRM) de l'idiome. La durée de vie d'un descripteur de fichier est géré automatiquement, tout comme la durée de vie d'un objet alloué dynamiquement est géré automatiquement. C++ n'est pas besoin d'un IDisposable, using, ou un finally parce que déterministe, la destruction peut être utilisé pour nettoyer quoi que ce soit.

Oui, en C++, il peut arriver que vous devez écrire votre propre SBRM conteneur pour gérer une ressource, mais il est rare. Plus moderne de bibliothèques (en particulier ceux inclus dans Boost) utiliser le SBRM idiome. Même si vous n'avez pas à écrire une, c'est simple et c'est écrire une fois, utilisez-partout.

L'énorme avantage du C++ approche alors est-ce que parce que l'objet des durées de vie sont déterministes, objet de toutes les durées de vie peuvent être gérés de manière uniforme à l'aide de la SBRM idiome, et par l'utilisation de cet idiome, objet de toutes les durées de vie peuvent être gérées automatiquement.

De ce fait, je ne pense pas qu'il est possible de dire qu'il est plus facile d'écrire du code lorsque vous avez la collecte des ordures. Bien sûr, si vous n'avez jamais utiliser un autre type de ressource, vous êtes bon pour aller, mais comment de nombreux programmes n'utilisez jamais un non-mémoire de ressources?

(Notez que je ne dis pas que la collecte des ordures est inutile. Il peut offrir des avantages de performance; je ne sais pas vraiment. Il peut aider à réduire la fragmentation du segment. Il peut aider beaucoup de choses. Je me concentre uniquement sur la facilité d'utilisation ici.)

35voto

Alexandre C. Points 31758

La différence est que dans l’objet C++ destruction est déterministe: vous savez que lorsque tous les pointeurs partagés qui pointent vers les mêmes objets sont détruits, les objets sont détruits.

# GC, au contraire, est non déterministe: vous ne pouvez pas dire quand la mémoire est libérée, c’est à la GC de le faire périodiquement.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X