J'écris une application très haute performance qui gère et traite des centaines d'événements chaque milliseconde. P>
est non géré plus rapide C ++ que géré C ++? et pourquoi? p>
Les offres géales C ++ gérées avec CLR au lieu de OS et CLR prend en charge la gestion de la mémoire, ce qui simplifie le code et est probablement également plus efficace que le code écrit par "un programmeur" dans le C ++ non géré? ou il y a une autre raison? Lorsque vous utilisez géré, comment peut-on peut-on éviter une allocation de mémoire dynamique, ce qui provoque une touche de performance, s'il est tout transparent au programmeur et géré par CLR? P>
Revenez donc à ma question, est géré C ++ plus efficace en termes de vitesse que non gérés C ++ et pourquoi? P>
9 Réponses :
n'est pas c ++ / cli une langue interprétée à moitié comme Java? P>
En outre, une personne n'a-t-elle pas posé une étude d'une étude qui a montré que les systèmes GC sont toujours plus lents que non GC? P>
Il n'y a personne de réponse à cela. En tant que vraiment général em> règle, le code natif sera généralement plus rapide, mais 1) qui est pas toujours le cas, 2) parfois la différence est trop faible pour se soucier, et 3) la façon dont le code est écrit habituellement faire plus de différence que géré par rapport non géré. p>
Le code géré fonctionne dans une machine virtuelle. Fondamentalement, vous commencez avec un compilateur qui produit des codes d'octets en sortie, puis alimenter que la machine virtuelle. La machine virtuelle recompose ensuite à la machine à la machine et exécute cela. Cela peut donner de réels avantages dans certaines circonstances. Pour un exemple, si vous avez un processeur 64 bits en cours d'exécution 64 bits VM (à peu près une donnée plus) mais et ancien programme écrit avant les processeurs 64 bits étaient communs, la machine virtuelle encore compiler ce code d'octet à 64- Code de la machine à bits, qui peut donner un avantage de vitesse assez substantiel pour au moins un code. p>
Dans le même temps, il peut également s'agir d'un désavantage assez notable pour certains code. En particulier, le compilateur est en cours d'exécution pendant que l'utilisateur attend. Pour répondre à cela, ne peut pas se lancer très lentement compilateur de la machine virtuelle. Bien que les générateurs de code natif diffèrent, il existe une assez bonne chance que quel que soit le compilateur natif que vous choisissez inclut au moins quelques optimisations qui ont été abandonnées dans le compilateur ByTecode de la VM afin de conserver son utilisation de ressources raisonnable. P>
Le VM utilise également un collecteur à ordures. Les collectionneurs à ordures ont des caractéristiques assez différentes de la gestion manuelle de la mémoire. Avec de nombreux gestionnaires manuels, l'allocation de mémoire est assez chère. La mémoire de libération est assez bon marché, mais à peu près linéaire sur le nombre d'articles que vous publiez. D'autres gestionnaires manuels inverseront grossièrement cela, faisant des travaux supplémentaires lors de la libération de la mémoire afin de rendre la répartition plus rapide. De toute façon, la structure des coûts est différente d'un collecteur typique. P>
Avec un collecteur à ordures, l'allocation de mémoire est généralement très em> pas cher. Avec un collecteur typique (copie), le coût de la libération de mémoire dépend principalement du nombre d'objets qui ont été attribués et sont encore (au moins potentiellement) en cours d'utilisation. P>
Les allocations elles-mêmes diffèrent cependant. En C ++ natif, vous créez généralement la plupart des objets sur la pile, où les deux alloue et em> libérer de la mémoire est extrêmement pas cher. Dans le code géré, vous allouez généralement un pourcentage de mémoire beaucoup plus important de manière dynamique, où il est recueilli. P>
Pourquoi est-ce plus rapide et quand cela ne sera pas le cas?
@bsabaid: Il n'y a pas de CLR VM Traduire.
La traduction du code de machine ne se produit qu'une seule fois. Si j'exécute la même ligne de code de plusieurs fois, je pense que cette traduction n'a pas d'importance. Oui, le point de collecteur des ordures que vous avez fabriqué est important et la répartition de la mémoire dynamique. Existe-t-il un échantillon disponible dans lequel vous prévenez une grande partie de la mémoire à utiliser afin d'éviter que Dynamic Malloc? Est-il possible de faire en C #?
@Jerry Coffin Vous décrivez le comportement du Hotspot VM Java Hotspot. Il s'agit d'abord (rapide) sur la première demande que de détecter les boucles chaudes (c'est l'endroit où le nom vient) et les recompille avec des optimisations non trop mauvaises. Malheureusement, le .NET CLR (4) ne le fait toujours pas.
@bsObaid, oui on pourrait mettre un grand chunck de mémoire pour éviter MALLOC, en utilisant de grandes variables globales, mais la fonction locale des petites variables fonctionne généralement plus rapidement. Bien que les situations extrêmes nécessitent des solutions extrêmes et que vous devez tester ceux-ci. c'est difficile à dire sauf si vous l'avez testé
Vous pouvez écrire du code lent dans n'importe quelle langue; Inversement, vous pouvez utiliser des algorithmes décents qui pourraient bien être rapides, c'est presque n'importe quelle langue. P>
La réponse commune ici serait de choisir une langue que vous connaissez déjà, utilisez des algorithmes appropriés, puis profilez-le de le diable pour déterminer les points chauds. P>
Je suis quelque peu préoccupé par les centaines d'événements chaque énoncé milliseconde em>. C'est un terrain terrible. Allez-vous raisonnablement pour pouvoir faire le traitement que vous attendez dans toute langue em>? P>
En tant que développeur C ++ sur des systèmes hautes performances, j'ai tendance à faire confiance à ma capacité à profiler et à optimiser le code émis. Cela dit; Il existe de très hautes performances. Les applications .NET sont très performantes, où l'auteur s'est efforcé de ne pas faire une allocation de mémoire dynamique à l'intérieur des boucles critiques - principalement en utilisant des pools alloués d'objets créés à l'avance. P>
Pour répéter mon commentaire précédent: choisissez ce que vous savez déjà, puis chanter. Même si vous frappez une impasse; Vous saurez probablement beaucoup plus sur votre espace problématique. P>
"Allocation de mémoire dynamique à l'intérieur des boucles critiques - principalement en utilisant des pools alloués d'objets créés à l'avance." Un peu hors sujet, mais est-il possible de le faire en utilisant c #? Y a-t-il des échantillons disponibles pour le faire en C ++? "Des centaines d'événements chaque milliseconde" vous obtenez ces nombreux lorsque vous analysez les données de données de marché à partir de différents échanges
C ++ - Jetez un coup d'œil à Boost :: Piscine C # - Je ne suis pas aussi conversant, mais comprenez-y peut / a été fait
Merci, c'était un plomb utile. la piscine l'a. Boos n'est pas célèbre pour sa vitesse. Utilisez-vous pour vos applications hautes performances? Je suis principalement un développeur C #, mais maintenant je suis entrant dans le monde C ++. C'est un must pour les développeurs HFT.
Dans le pire des cas, vous pouvez toujours mettre en œuvre vos allocateurs de pools de mémoire, vous ne dépendez pas de la bibliothèque. Évidemment, cette approche a également des inconvénients ..
Tout dépend de la situation. P>
Des choses qui font du code non géré le code plus rapide / géré plus lentement: p>
Les choses qui font du code géré plus rapidement / non géré plus lentement: p>
et probablement il y a beaucoup plus de raisons. p>
"Le code doit être converti en code de la machine avant de pouvoir être exécuté" mais c'est une chose une fois, elle n'effibarde pas la performance globale, n'est-ce pas?
Dépend souvent de vous exécuter le même code (une seule fois ou des millions de fois). En pratique, cela n'aura probablement pas d'importance.
Le code non géré peut être transformé spécifique par des goulottes de barreaux de ramification en fonction de la détection du processeur d'exécution du processeur. Le compilateur Intel C ++ peut automatiquement faire cela, par exemple, bien que des types d'instructions spécifiques et (controversalement) uniquement pour les processeurs Intel.
Il y a beaucoup de bonnes réponses ici, mais un aspect du code géré pouvant donner un avantage à long terme est l'analyse d'exécution. Étant donné que le code généré par le compilateur géré est un format intermédiaire, le code de la machine qui exécute réellement peut être optimisé en fonction de l'utilisation réelle. Si un sous-ensemble de fonctionnalités particuliers est fortement utilisé, le Jitteur peut localiser le code de la machine sur la même page de mémoire, augmentant la localité. Si un sous-appel particulier est effectué à plusieurs reprises d'une méthode particulière, un Jitteur peut le signaler de manière dynamique. p>
Il s'agit d'une amélioration par rapport au code non géré, où l'inlinage doit être "devinée" à l'avance et l'affranchissement excessif est nocif car il gonfle la taille du code et provoque des problèmes de localité causant (très chère coûteux) L2 / L1 Misses de cache. Cette information n'est tout simplement pas disponible pour l'analyse statique. Il n'est donc possible que dans un environnement jit'ing. Il y a un goody panier de victoires possibles à partir d'analyses d'exécution telles que la boucle optimisée de déroulement, etc. p>
Je ne prétends pas que le jitteur .Net est aussi intelligent que possible, mais je sais que j'ai entendu parler des caractéristiques d'analyse mondiales et je sais que beaucoup de recherches sur l'analyse d'exécution ont été effectuées à Hewlett-Packard. et d'autres entreprises. P>
Une question de base, par analyse de temps d'exécution, vous entendez un profilage? Comment faites-vous une analyse du temps d'exécution de votre code?
Une implémentation serait que la structure .NET commence à exécuter l'exécution d'une assemblée gérée en interprétant les codes d'octets CLR et la fréquence d'exécution de l'exécution des opérations, une corrélation élevée entre l'exécution d'une routine et une exécution d'un sous-programme de la routine, etc., etc. Générez ensuite un code de machine Profitant de ces connaissances pour minimiser les frais généraux (construction de pile d'appels / destruction, incrémentation et sauts de boucle, régions de mémoire "chaudes" fragmentées, etc.) dans des opérations fréquemment exécutées.
Ce serait un très bon moyen de régler le code, mais très difficile pour moi de faire ... comme notification Exec Freq de Opcodes, etc.
Pour être juste si vous utilisez un code natif, vous pouvez utiliser PGO dans VC ++ (probablement d'autres outils d'outils ont quelque chose comme celui-ci) pour faire une optimisation guidée profilée de l'application. Vous spéculez cela pourrait exister pour réussir - je sais pour un fait qu'il existe pour au moins un outil d'ensemble natif.
Premièrement, votre déclaration "traite des centaines d'événements chaque milliseconde". Cela semble assez irréaliste. Sauf si vous avez un module d'horloge conçu spécial sur l'ordinateur, je ne pense pas que vous puissiez atteindre l'objectif avec un PC générique (une résolution typique est d'environ 10 millisecondes). Deuxièmement, le Native C ++ est vaste mieux en termes de performance. Il y a beaucoup d'optimisation peut être prise en termes de C ++ pour accélérer, tandis que dans le code géré, ils ne sont pas possibles. Sachez également que la collecte des ordures dans le code géré rend la performance imprévisible --Lorsque GC incendie tout le processus est gelé. Une fois que vous avez rencontré le problème, la solution est plus douloureuse, maintenant tout le "beau style" offert par le code géré sera parti. p>
Tant que la capacité qui gère le code peut optimiser pour la CPU, elle est vraie, mais vous pouvez profiter des fonctions CPU (SSE2, MMX, etc.) dans Native C ++. Basé sur mon expérience, le boost de performance est négligeable. p>
avoir à être en désaccord avec vous sur la granularité 10ms tbh
"Il est possible de prendre beaucoup d'optimisation de C ++ pour accélérer, tandis que dans le code géré, ils ne sont pas possibles." - C'est faux. Le code géré n'utilise pas l'utilisation du collecteur des ordures, il ne l'utilise que par défaut. Les mêmes optimisations gagnées par une utilisation manuelle de la mémoire sont disponibles pour une utilisation dans C #. Vous pouvez déboguer de la mémoire, des registres, des drapeaux de processeur et de manipuler la pile en C # comme vous le pouvez avec C ++. Il est possible d'exécuter une ASM crue si vous sautez à travers des cerceaux.
Ecrire un code rapide, c'est toujours une douleur. Le problème principal que vous pouvez optimiser uniquement pour une plate-forme. C'est vraiment un cas sur la console, la plate-forme intégrée ou autre où le matériel est toujours le même. Dans le vrai monde PC, ce n'est pas le cas. Différents noyau, différente ISTRUCTION ECC ... Faites cela un cauchemar. C'est le problème principal, IMHO, qui fait vraiment la différence entre le code de l'homme / unam. Homme. Le code peut être optimiste optimisable pour la nouvelle plate-forme lorsque sa course est exécutée. Unman code non, est écrit dans la pierre. p>
Le code managé est dans la plupart des cas plus lents que le code non géré, même si le CLR .NET fait toujours une compilation JIT avant d'exécuter le code (il n'est pas compilé plusieurs fois alors que le programme est en cours d'exécution, mais il interprète bien jamais le code) . p>
Le problème est plutôt avec de nombreux contrôles de la CLR, par exemple exerce ses pour voir si vous exécutez sur les limites d'un tableau à chaque fois que vous essayez d'y accéder. Cela conduit à moins de problèmes avec les dépassements de tampon, etc., mais signifie également une baisse de performance en raison de la surcharge supplémentaire de ces contrôles. P>
J'ai vu des expériences où C # surperformé C ++, mais ceux qui ont été menées avec le code en prenant largement avantage des hiérarchies d'objets, etc. Quand il revient au numéro crissement et que vous voulez tirer le meilleur parti de votre PC, vous devrez aller avec le code non géré. p>
Un autre point a également été déjà mentionné - les fils de GC à des pauses un peu imprévisible dans l'exécution des programmes lorsque la mémoire doit être libéré. Vous avez besoin cette fois-ci lorsque vous faites la gestion de la mémoire dans le code non géré, mais il se produit plus souvent et chaque fois que vous décidez de détruire un objet qui signifie ne est pas tout fait à la fois pour l'ensemble du programme, de sorte que vous n'avez pas une longue pause. < / p>
La clé de la performance - en particulier, mais pas seulement pour NumberChrunching - est la gestion de la mémoire. C'est le goulot d'étranglement! Si vous parvenez à obtenir une utilisation plus efficace de la mémoire, vous obtiendrez plus de vitesse d'exécution. Les langues gérés apportent toutes les options pour le faire et une syntaxe plus pratique pour l'utilisateur (IMPO). Par conséquent, votre déclaration semble trop générale. Voir: Stackoverflow.com/a/9327983/1215993
dans l'ordre de vitesse et d'alimentation L'ASM> C> C ++> = C ++ / CLI> C #> = Toutes les autres. Mais créer un service Web dans ASM est une longue douleur. Ensuite, utilisez le bon langage pour le bon travail et le bon public pour faire le meilleur travail, à l'heure donnée. P>
Qu'est-ce qui est géré C ++? C ++ / CLI?
@Nikko: Géré C ++ est le prédécesseur de C ++ / CLI.
@Jerry, True, mais beaucoup qui viennent plus récemment à C ++ / CLI, cela a géré C ++ car il possède une syntaxe C ++ et produit du code géré. Ils ne savent pas que c'était le nom de quelque chose d'autre. Notez la question indiquée gérée C ++ non gérée C ++.