Combien plus rapide est C ++ que C #?

246

Ou est-ce maintenant l'inverse?

D'après ce que j'ai entendu, il y a des domaines dans lesquels C # s'avère plus rapide que C ++, mais je n'ai jamais eu le courage de le tester par moi-même.

Je pensais que vous pourriez expliquer ces différences en détail ou me diriger vers le bon endroit pour obtenir des informations à ce sujet.

Prendre au piège
la source
7
Protégé, pour empêcher la publication de repères aléatoires. Si vous pensez pouvoir faire valoir vos arguments, vous aurez besoin de 10 représentants pour le faire.
Robert Harvey
2
Comment cela n'est-il pas fermé comme opinion / argumentatif de toute façon? Ne suis-je pas encore sur StackOverflow? (Ne pas suggérer la fin, juste curieux. J'adore les questions qui stimulent les arguments d'opinion)
Bill K
1
C'est presque une question théorique, étant donné que nous vivons à une époque où l'IL peut être converti en CPP et optimisé à partir de là: docs.unity3d.com/Manual/IL2CPP.html
pixelpax
Un langage qui vérifie l'accès hors de portée de la baie ne surpassera jamais celui qui ne le fait pas.
Seva Alekseyev
@SevaAlekseyev Ce n'est pas la langue qui fait ça mais le compilateur. L'une des raisons pour lesquelles C ++ est si rapide (à part les plus évidentes) est que les compilateurs C ++ existent depuis 35 ans (sinon plus). Rien n'empêche les compilateurs C # de s'améliorer avec le temps. Pour le cas que vous mentionnez, veuillez lire ce stackoverflow.com/questions/16713076/…
Piège

Réponses:

343

Il n'y a aucune raison stricte pour laquelle un langage basé sur le bytecode comme C # ou Java qui a un JIT ne peut pas être aussi rapide que le code C ++. Cependant, le code C ++ était beaucoup plus rapide pendant longtemps, et l'est encore aujourd'hui dans de nombreux cas. Cela est principalement dû au fait que les optimisations JIT les plus avancées sont compliquées à mettre en œuvre, et les vraiment cool n'arrivent que maintenant.

C ++ est donc plus rapide, dans de nombreux cas. Mais ce n'est qu'une partie de la réponse. Les cas où C ++ est en fait plus rapide, sont des programmes hautement optimisés, où des programmeurs experts ont complètement optimisé le code. Non seulement cela prend beaucoup de temps (et donc est cher), mais cela entraîne aussi généralement des erreurs dues à des optimisations excessives.

D'un autre côté, le code dans les langages interprétés devient plus rapide dans les versions ultérieures du runtime (.NET CLR ou Java VM), sans que vous ne fassiez rien. Et il y a beaucoup d'optimisations utiles que les compilateurs JIT peuvent faire qui sont tout simplement impossibles dans les langages avec des pointeurs. En outre, certains soutiennent que la récupération de place doit généralement être aussi rapide ou plus rapide que la gestion manuelle de la mémoire, et dans de nombreux cas, elle l'est. Vous pouvez généralement implémenter et réaliser tout cela en C ++ ou C, mais cela va être beaucoup plus compliqué et sujet aux erreurs.

Comme l'a dit Donald Knuth, "l'optimisation prématurée est la racine de tout mal". Si vous savez vraiment avec certitude que votre application consistera principalement en arithmétique très critique en termes de performances, et qu'elle constituera le goulot d'étranglement, et qu'elle sera certainement plus rapide en C ++, et vous êtes sûr que C ++ n'entrera pas en conflit avec les autres exigences, optez pour C ++. Dans tous les autres cas, concentrez-vous d'abord sur l'implémentation correcte de votre application dans la langue qui vous convient le mieux, puis trouvez les goulots d'étranglement des performances si elle s'exécute trop lentement, puis réfléchissez à la façon d'optimiser le code. Dans le pire des cas, vous devrez peut-être appeler le code C via une interface de fonction étrangère, vous aurez donc toujours la possibilité d'écrire des parties critiques dans un langage de niveau inférieur.

Gardez à l'esprit qu'il est relativement facile d'optimiser un programme correct, mais beaucoup plus difficile de corriger un programme optimisé.

Il est impossible de donner des pourcentages réels d'avantages de vitesse, cela dépend en grande partie de votre code. Dans de nombreux cas, l'implémentation du langage de programmation n'est même pas le goulot d'étranglement. Prenez les références sur http://benchmarksgame.alioth.debian.org/ avec beaucoup de scepticisme, car elles testent largement le code arithmétique, qui n'est probablement pas du tout similaire à votre code.

Martin Probst
la source
92
Le code <quote> dans les langages interprétés devient plus rapide dans les versions ultérieures du runtime </quote> Comme le code compilé par une meilleure version du compilateur sera également plus rapide.
Martin York
47
En fait, il y a au moins une raison: JIT doit être rapide et ne peut pas se permettre de passer du temps sur diverses optimisations avancées disponibles pour un compilateur C ++.
Nemanja Trifunovic
63
"mais conduit aussi fréquemment à des erreurs dues à des optimisations excessives." [citation désespérément nécessaire]. Je travaille dans un laboratoire national et nous optimisons l'enfer de notre code. Cela n'entraîne généralement pas de code bogué.
Todd Gamblin
35
"Il est relativement facile d'optimiser un programme correct, mais beaucoup plus difficile de corriger un programme optimisé."
gradbot
20
Inge: je ne suis pas sûr que vous soyez sur la bonne voie. Oui, C # est implémenté dans un autre langage, mais le compilateur JIT génère du code machine, donc ce n'est pas un langage interprété. Il n'est donc pas limité par son implémentation C ++. Je ne sais pas pourquoi vous pensez que l'ajout d'un gestionnaire à quelque chose le rend intrinsèquement plus rapide.
Martin Probst
202

C # n'est peut-être pas plus rapide, mais il vous rend plus rapide. C'est la mesure la plus importante pour ce que je fais. :)

mattlant
la source
68
Haha, il y a une bonne citation de Larry Wall sur le sujet. Il parle de Perl, mais cela peut être pensé pour toutes les discussions concernant les langages et les performances: ".. les langages informatiques antérieurs, tels que Fortran et C, ont été conçus pour utiliser efficacement un matériel informatique coûteux. En revanche, Perl est conçu pour faire un usage efficace de programmeurs informatiques coûteux "
Falaina
60
1. "C # est beaucoup plus rapide que C ++" 2. "Ce ne peut pas être vrai" 1. "Bien sûr que c'est possible" 2. "De combien?" 1. "Habituellement de 3 à 4 mois"
Dmitry S.
2
pour C ++ qui dépend vraiment des bibliothèques que vous utilisez, C # n'est généralement pas plus rapide, .NET l'est lorsque vous parlez de productivité
Ion Todirel
C'est la même raison pour laquelle vous pouvez utiliser Python au lieu de C pour écrire du code ... mais après avoir créé des calculs lourds, vous pouvez sentir la différence de performances.
Ch3shire
Cela dépend de ce à quoi vous êtes habitué. Je programme beaucoup plus vite en C ++ que je ne l'aurais fait en C #. Les connaissances en bibliothèque en sont une grande partie, car vous ne voulez pas réinventer la roue pour les tâches de base. Le problème principal de C / C ++ était la gestion des pointeurs qui est à peu près résolue avec des pointeurs intelligents. Cela dit, C ++ sérieux manque d'une bibliothèque étendue comme les offres .NET et Java et cela peut accélérer considérablement le développement. Cela ne sera pas résolu bientôt car ces garçons standard aiment passer leur temps à améliorer les modèles plutôt qu'aux extensions de bibliothèque.
gast128
87

C'est cinq oranges plus rapides. Ou plutôt: il ne peut y avoir de réponse globale (correcte). C ++ est un langage compilé statiquement (mais il y a aussi une optimisation guidée par profil), C # s'exécute aidé par un compilateur JIT. Il y a tellement de différences qu'il est impossible de répondre à des questions comme «à quelle vitesse», même en donnant des ordres de grandeur.

Konrad Rudolph
la source
177
Avez-vous des preuves à l'appui de votre scandaleuse revendication des cinq oranges? Mes expériences pointent toutes vers 2 oranges au maximum, avec une amélioration de 3 mangues lors de la métaprogrammation du modèle.
Alex
42
À la levure, il ne fait pas de palourdes, ses hors-d'œuvre sont plus rapides.
Chris
11
D'après mon expérience, c'est plutôt 5,2 oranges. Mais cela dépend du fruit-o-mètre que vous utilisez.
Dio F
4
Mise à jour, StackOverflow lui-même a foiré et gère les commentaires inefficaces, donc moins de bananes (300 bananes pire que ce qui devrait être): meta.stackexchange.com/questions/254534/…
KeksArmee
87

Je vais commencer par être en désaccord avec une partie de la réponse acceptée (et bien votée) à cette question en déclarant:

Il y a en fait beaucoup de raisons pour lesquelles le code JITted fonctionnera plus lentement qu'un programme C ++ correctement optimisé (ou tout autre langage sans surcharge d'exécution), notamment:

  • les cycles de calcul consacrés au code JITting lors de l'exécution ne sont par définition pas disponibles pour une utilisation dans l'exécution du programme.

  • tous les chemins chauds dans le JITter seront en concurrence avec votre code pour le cache d'instructions et de données dans le CPU. Nous savons que le cache domine en termes de performances et que les langages natifs comme C ++ n'ont pas ce type de conflit, par définition.

  • le budget-temps d'un optimiseur au moment de l'exécution est nécessairement beaucoup plus contraint que celui d'un optimiseur au moment de la compilation (comme l'a souligné un autre intervenant)

Bottom line: En fin de compte, vous voulez presque certainement en mesure de créer une implémentation plus rapide en C ++ que vous ne le pourriez en C # .

Maintenant, cela dit, combien plus rapide n'est vraiment pas quantifiable, car il y a trop de variables: la tâche, le domaine du problème, le matériel, la qualité des implémentations et de nombreux autres facteurs. Vous devrez exécuter des tests sur votre scénario pour déterminer la différence de performances, puis décider s'il vaut la peine de l'effort et de la complexité supplémentaires.

C'est un sujet très long et complexe, mais je pense qu'il vaut la peine de mentionner pour être complet que l'optimiseur d'exécution de C # est excellent, et est capable d'effectuer certaines optimisations dynamiques lors de l'exécution qui ne sont tout simplement pas disponibles pour C ++ avec son temps de compilation ( optimiseur statique). Même avec cela, l'avantage est toujours profondément ancré dans la cour de l'application native, mais l'optimiseur dynamique est la raison du " presque qualificatif certainement" donné ci-dessus.

-

En termes de performances relatives, j'ai également été troublé par les chiffres et les discussions que j'ai vus dans certaines autres réponses, j'ai donc pensé que je ferais sonner la voix et, en même temps, apporterais un certain soutien aux déclarations que j'ai faites ci-dessus.

Une grande partie du problème avec ces benchmarks est que vous ne pouvez pas écrire de code C ++ comme si vous écriviez C # et espérez obtenir des résultats représentatifs (par exemple, effectuer des milliers d'allocations de mémoire en C ++ va vous donner des chiffres terribles.)

Au lieu de cela, j'ai écrit un code C ++ légèrement plus idiomatique et comparé au code C # @Wiory fourni. Les deux changements majeurs que j'ai apportés au code C ++ étaient:

1) utilisé vector :: reserve ()

2) aplati le tableau 2d à 1d pour obtenir une meilleure localité de cache (bloc contigu)

C # (.NET 4.6.1)

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);
}

Durée d'exécution (Release): Init: 124ms, Fill: 165ms

C ++ 14 (Clang v3.8 / C2)

#include <iostream>
#include <vector>

auto TestSuite::ColMajorArray()
{
    constexpr size_t ROWS = 5000;
    constexpr size_t COLS = 9000;

    auto initStart = std::chrono::steady_clock::now();

    auto arr = std::vector<double>();
    arr.reserve(ROWS * COLS);

    auto initFinish = std::chrono::steady_clock::now();
    auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);

    auto fillStart = std::chrono::steady_clock::now();

    for(auto i = 0, r = 0; r < ROWS; ++r)
    {
        for (auto c = 0; c < COLS; ++c)
        {
            arr[i++] = static_cast<double>(r * c);
        }
    }

    auto fillFinish = std::chrono::steady_clock::now();
    auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);

    return std::make_pair(initTime, fillTime);
}

Durée d'exécution (Release): Init: 398µs (oui, c'est microsecondes), Fill: 152ms

Temps d'exécution total: C #: 289 ms, C ++ 152 ms (environ 90% plus rapide)

Observations

  • La modification de l'implémentation C # en la même implémentation de tableau 1d a donné Init: 40ms, Fill: 171ms, Total: 211ms ( C ++ était toujours presque 40% plus rapide ).

  • Il est beaucoup plus difficile de concevoir et d'écrire du code "rapide" en C ++ que d'écrire du code "normal" dans les deux langues.

  • Il est (peut-être) étonnamment facile d'obtenir de mauvaises performances en C ++; nous l'avons vu avec des performances de vecteurs non réservés. Et il y a beaucoup de pièges comme celui-ci.

  • Les performances de C # sont plutôt étonnantes quand on considère tout ce qui se passe au moment de l'exécution. Et cette performance est relativement facile d'accès.

  • Plus de données anecdotiques comparant les performances de C ++ et C #: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

L'essentiel est que C ++ vous donne beaucoup plus de contrôle sur les performances. Voulez-vous utiliser un pointeur? Une référence? Empiler la mémoire? Tas? Polymorphisme dynamique ou éliminer la surcharge d'exécution d'une table virtuelle avec polymorphisme statique (via des modèles / CRTP)? En C ++, vous devez ... euh, accéder à faire tous ces choix (et plus) vous, idéalement afin que vos meilleures adresses de solution du problème que vous vous attaquez.

Demandez-vous si vous voulez ou avez réellement besoin de ce contrôle, car même pour l'exemple trivial ci-dessus, vous pouvez voir que bien qu'il y ait une amélioration significative des performances, il nécessite un investissement plus profond pour y accéder.

U007D
la source
16
@Quonux merci pour le commentaire. Bien sûr, ce n'est pas un "vrai programme". Le point de référence était de refactoriser un benchmark C # proposé ailleurs sur cette page comme preuve que le code JITted est en quelque sorte plus rapide que natif - ce n'est pas le cas, et le benchmark était potentiellement trompeur pour les nouvelles personnes.
U007D
9
@Quonux pourquoi faut-il écrire comme ça? Ce sont des gens comme vous qui me font détester le stackoverflow.
Markus Knappen Johansson
5
@MarkusKnappenJohansson J'ai eu une mauvaise journée;), je suis juste un humain aussi, a supprimé mon downvote, mais mon opinion s'applique toujours. Oh s'il vous plaît, ne détestez pas SO juste parce qu'il y a des gens "stupides" :). Avoir une belle.
Quonux
9
RÉFÉRENCE COMPLÈTEMENT TROMPEUSE. Dans la version C ++, vous réservez simplement une partie de la mémoire (puis vous vous demandez comment cette opération prend des microsecondes pour s'exécuter). Dans la version C #, vous créez 5000 ARRAYS (instanciation d'objets en mémoire). C ++ est plus rapide que C # ... mais la différence est loin d'être proche de 40% ... en ce moment, il est plus dans une plage <10%. Ce que votre exemple illustre, c'est que les programmeurs doivent s'en tenir à la langue de leur choix (et d'après votre profil, il est évident que vous êtes programmeur C ++ de carrière). En C #, vous pouvez faire un tableau 2D int[,]... suivi d'un exemple.
nikib3ro
3
D'après ce que je peux dire, le code de votre exemple C ++ alloue littéralement à l'avance la mémoire. L'implémentation C # appropriée écrirait simplement `` List <double> arrs = new List <double> (ROWS * COLS) '' qui alloue la mémoire requise pour indexer un tableau à 2 dimensions au format à 1 dimension (par exemple, ce que vous avez fait en C ++). Il n'y a absolument aucune raison d'allouer un tableau bidimensionnel et de l'aplatir manuellement - la quantité massive d'itérations dans votre pré-test est la cause des performances de merde. J'imagine que les frais généraux seraient encore plus en C #, mais pas d'une quantité considérable.
JDSweetBeat
62

D'après mon expérience (et j'ai beaucoup travaillé avec les deux langages), le principal problème avec C # par rapport à C ++ est la consommation élevée de mémoire, et je n'ai pas trouvé de bon moyen de le contrôler. C'était la consommation de mémoire qui ralentirait finalement le logiciel .NET.

Un autre facteur est que le compilateur JIT ne peut pas se permettre trop de temps pour effectuer des optimisations avancées, car il s'exécute au moment de l'exécution, et l'utilisateur final le remarquerait s'il prend trop de temps. D'un autre côté, un compilateur C ++ dispose de tout le temps nécessaire pour effectuer des optimisations au moment de la compilation. Ce facteur est beaucoup moins important que la consommation de mémoire, à mon humble avis.

Nemanja Trifunovic
la source
6
Dans un projet à l'œuvre, nous avons dû extraire des quantités gigantesques de données, notamment en conservant simultanément plusieurs Go en mémoire et en effectuant des calculs coûteux sur tout cela - cela nécessitait un contrôle précis de toutes les allocations, C ++ était à peu près le seul choix. +1 pour C ++. D'un autre côté, ce n'était qu'un projet, nous avons passé la majeure partie de notre temps à écrire des systèmes qui interagissaient avec des simulateurs lents, et le débogage pouvait être un cauchemar, alors j'aurais souhaité pouvoir utiliser un langage d'optimisation du temps du programmeur pour tous ces autres des trucs.
Bogatyr
7
@IngeHenriksen: Je connais bien le modèle Dispose, mais cela n'aide pas du tout avec la mémoire gérée.
Nemanja Trifunovic
10
@IngeHenriksen le supprimer garantit uniquement que la méthode Dispose a été appelée. L'élimination ne libère jamais la mémoire récupérée. La méthode Dispose est uniquement destinée au nettoyage des ressources non gérées comme les descripteurs de fichiers et n'a rien à voir avec la gestion de la mémoire.
doug65536
1
@NemanjaTrifunovic: "Le compilateur JIT ne peut pas se permettre trop de temps pour effectuer des optimisations avancées". Pouvez-vous citer des optimisations qui ne sont pas effectuées par les JIT car elles prendraient trop de temps?
Jon Harrop
5
@ user3800527: Même si l'ajout de RAM a toujours été possible (et ce n'est pas le cas - imaginez que Microsoft ajoute de la RAM à chaque utilisateur MS Office), cela ne résoudra pas le problème. La mémoire est hiérarchique et un programme C # aura beaucoup plus d'échecs de cache qu'un programme C ++.
Nemanja Trifunovic
35

Un scénario particulier où le C ++ a toujours le dessus (et le sera, pour les années à venir) se produit lorsque les décisions polymorphes peuvent être prédéterminées au moment de la compilation.

En règle générale, l'encapsulation et la prise de décision différée sont une bonne chose car elles rendent le code plus dynamique, plus facile à adapter aux exigences changeantes et plus facile à utiliser comme cadre. C'est pourquoi la programmation orientée objet en C # est très productive et peut être généralisée sous le terme de «généralisation». Malheureusement, ce type particulier de généralisation a un coût au moment de l'exécution.

Habituellement, ce coût n'est pas substantiel, mais il existe des applications où les frais généraux d'appels de méthode virtuelle et de création d'objet peuvent faire la différence (d'autant plus que les méthodes virtuelles empêchent d'autres optimisations telles que l'inlining d'appel de méthode). C'est là que C ++ a un énorme avantage car vous pouvez utiliser des modèles pour réaliser un type de généralisation différent qui n'a aucun impact sur l'exécution mais n'est pas nécessairement moins polymorphe que la POO. En fait, tous les mécanismes qui constituent la POO peuvent être modélisés en utilisant uniquement des techniques de modèle et une résolution au moment de la compilation.

Dans de tels cas (et certes, ils sont souvent limités à des domaines à problèmes spéciaux), C ++ gagne contre C # et des langages comparables.

Konrad Rudolph
la source
6
En fait, les machines virtuelles Java (et probablement .NET) font de grands efforts pour éviter la répartition dynamique. Fondamentalement, s'il existe un moyen d'éviter les polymorphes, vous pouvez être sûr que votre machine virtuelle le fera.
Martin Probst
3
+1 J'ai toujours du mal à l'expliquer à mes collègues C # qui connaissent peu le C ++ d'une manière qui leur permettrait d'apprécier la signification. Vous l'avez bien expliqué.
Roman Starkov
9
@crtracy: vous faites votre pari sans applications informatiques hautes performances. Tenez compte des prévisions météorologiques, de la bioinformatique et des simulations numériques. L'avance des performances de C ++ dans ces domaines ne diminuera pas , car aucun autre code ne peut atteindre des performances comparables au même niveau d'abstraction élevée.
Konrad Rudolph
5
@Jon Pommes et oranges. Votre revendication spécifique était «C # est des ordres de grandeur plus rapides que C ++ dans le contexte de la métaprogrammation», et non «l'utilisation de code précompilé est des ordres de grandeur plus rapides que le code interprété». Pendant que nous y sommes, votre affirmation selon laquelle la génération de code d'exécution est «plus générale» que la génération de code au moment de la compilation est également clairement erronée - elles ont toutes les deux des forces et des faiblesses. La génération de code à la compilation utilise le système de type pour fournir une sécurité de type statique - la génération de code d'exécution ne peut pas le faire (elle peut fournir une sécurité de type forte, mais pas une sécurité de type statique ).
Konrad Rudolph
5
@ user3800527 Je pense que vous manquez tout l'intérêt de cette réponse. Bien sûr, vous pouvez contourner ce problème en interrompant l'encapsulation et en passant à des structures de bas niveau - vous pouvez écrire l'assembly dans (la plupart) n'importe quelle langue. Ce qui rend le C ++ (presque) unique, et particulièrement adapté à la programmation haute performance, c'est que vous pouvez créer des abstractions de haut niveau sans frais d'exécution. Vous n'avez donc pas besoin d'écrire du code de type assembleur en C ++ pour obtenir des performances supérieures: une sort(arr, generic_comparer)boucle bien écrite sera aussi efficace qu'une boucle manuscrite en C ++. Il ne sera jamais en C #.
Konrad Rudolph
20

C ++ (ou C d'ailleurs) vous donne un contrôle précis sur vos structures de données. Si vous voulez bit-twiddle vous avez cette option. Les grandes applications Java ou .NET gérées (OWB, Visual Studio 2005 ) qui utilisent les structures de données internes des bibliothèques Java / .NET transportent le bagage avec elles. J'ai vu des sessions de conception OWB utilisant plus de 400 Mo de RAM et BIDS pour la conception de cubes ou ETL entrer dans les 100 de Mo également.

Sur une charge de travail prévisible (comme la plupart des benchmarks qui répètent un processus plusieurs fois), un JIT peut vous obtenir un code suffisamment bien optimisé pour qu'il n'y ait pas de différence pratique.

OMI sur les grandes applications, la différence n'est pas tant le JIT que les structures de données que le code lui-même utilise. Lorsqu'une application est gourmande en mémoire, vous obtiendrez une utilisation du cache moins efficace. Les échecs de cache sur les processeurs modernes sont assez chers. Là où C ou C ++ gagne vraiment, c'est là que vous pouvez optimiser votre utilisation des structures de données pour bien jouer avec le cache du processeur.

ConcernedOfTunbridgeWells
la source
19

Pour les graphiques, la classe graphique C # standard est beaucoup plus lente que GDI accessible via C / C ++. Je sais que cela n'a rien à voir avec la langue en soi, plus avec la plate-forme .NET totale, mais Graphics est ce qui est proposé au développeur en remplacement de GDI, et ses performances sont si mauvaises que je n'oserais même pas faire de graphiques avec ça.

Nous avons un référentiel simple que nous utilisons pour voir à quelle vitesse une bibliothèque graphique est, et qui consiste simplement à dessiner des lignes aléatoires dans une fenêtre. C ++ / GDI est toujours accrocheur avec 10000 lignes tandis que C # / Graphics a du mal à en faire 1000 en temps réel.

QBziZ
la source
5
J'ai été intrigué par votre réponse. Avez-vous testé le même benchmark avec du code et des bits de verrouillage dangereux et dessiné vous-même les lignes aléatoires? Maintenant, ce serait une chose intéressante à regarder.
Pedery
2
@Pedery non, je ne l'ai pas. en utilisant simplement GDI et .NET.Graphics de la manière la plus élémentaire. que voulez-vous dire par "dessiner vous-même les lignes aléatoires"?
QBziZ
1
Ensuite, vous devriez peut-être envisager de tester cela pour obtenir une mesure plus réaliste de la vitesse à laquelle C # peut être. Voici un bon aperçu de la technique: bobpowell.net/lockingbits.htm
Pedery
6
Ce n'est pas ce que nous voulons faire, mettre nous-mêmes des pixels séparés dans un tampon d'image. Si vous devez tout implémenter vous-même, quel est l'intérêt d'avoir une API / plate-forme contre laquelle coder? Pour moi, c'est un non-argument. Nous n'avons jamais eu besoin de mettre des pixels séparés dans un tampon d'image dans GDI pour tracer des lignes, et nous ne prévoyons pas de le faire non plus dans .NET. À mon avis, nous avons utilisé une métrique réaliste et .NET s'est avéré lent.
QBziZ
1
Eh bien, j'ai juste une petite idée de ce qu'est la détection de blob, mais le simple fait de dire un timing ne prouve rien du tout. Vous en avez écrit un en C ++? En JavaScript? Et par rapport à ceux en C #? Et en plus de cela, je ne pense pas que la détection d'objets blob utilise de nombreuses primitives graphiques. Corrigez-moi si je me trompe, mais je suppose que ce sont des algorithmes statistiques effectuant des opérations sur les pixels.
QBziZ
13

Le garbage collection est la principale raison pour laquelle Java # NE PEUT PAS être utilisé pour les systèmes en temps réel.

  1. Quand le GC aura-t-il lieu?

  2. Combien de temps cela prendra-t-il?

Ce n'est pas déterministe.


la source
5
Je ne suis pas un grand fan de Java, mais rien ne dit que Java ne peut pas utiliser un GC convivial en temps réel.
Zan Lynx
5
Il y a beaucoup d'implémentations GC en temps réel si vous voulez regarder. (GC est une zone qui est débordait avec des papiers de recherche)
Arafangion
FWIW, Richard Jones vient de publier une version mise à jour de son livre sur la collecte des ordures qui couvre, entre autres, des conceptions GC en temps réel à la pointe de la technologie.
Jon Harrop
11
C'est un argument absurde, Windows (et Linux) ne sont pas des systèmes d'exploitation en temps réel. Votre code C ++ peut être échangé à tout moment pour un certain nombre d'emplacements de 18 ms.
Henk Holterman
2
@HenkHolterman Vrai, mais vous pouvez toujours écrire un chargeur de démarrage dans l'assembly, le lier dans un amorçage du noyau pour votre application et exécuter vos applications C ++ directement sur le matériel (dans RT btw). Vous ne pouvez pas faire cela en C # et tous les efforts que j'ai vus ne font qu'imiter un assemblage précompilé en C # et utiliser une tonne de code C, ce qui rend inutile l'utilisation de C #. Lire tout cela est un peu drôle, car C # est vraiment inutile sans le framework .NET.
zackery.fix
11

Nous avons dû déterminer si C # était comparable à C ++ en termes de performances et j'ai écrit quelques programmes de test pour cela (en utilisant Visual Studio 2005 pour les deux langages). Il s'est avéré que sans garbage collection et en ne considérant que le langage (pas le framework), C # a fondamentalement les mêmes performances que C ++. L'allocation de mémoire est beaucoup plus rapide en C # qu'en C ++ et C # a un léger avantage dans le déterminisme lorsque les tailles de données sont augmentées au-delà des limites de la ligne de cache. Cependant, tout cela a finalement dû être payé et il y a un coût énorme sous la forme de résultats de performances non déterministes pour C # en raison de la collecte des ordures.

ILoveFortran
la source
1
En C ++, vous avez la possibilité d'utiliser différentes méthodes d'allocation, donc selon la façon dont la mémoire a été allouée (AOT?) En C #, cela pourrait être fait de la même manière (mais beaucoup plus rapidement) en C ++.
zackery.fix
5
@ zackery.fix .NET a un avantage intéressant dans l'allocation de tas, car il n'a qu'à déplacer un pointeur pour allouer un nouvel objet. Cela n'est possible qu'en raison du compacteur de déchets. Bien sûr, vous pouvez faire la même chose en C ++, mais C ++ ne fait pas cela. C'est drôle de voir comment vous utilisez le même argument pour dire "C # pourrait mais ne le fait pas, c'est donc des ordures" et "C ++ ne le fait pas, mais c'est possible, donc c'est génial" :)
Luaan
9

Comme d'habitude, cela dépend de l'application. Il y a des cas où C # est probablement beaucoup plus lent et d'autres cas où C ++ est 5 ou 10 fois plus rapide, en particulier dans les cas où les opérations peuvent être facilement SIMD.

Shikari noir
la source
Le meilleur cas pour les machines virtuelles sera la compilation au moment de l'exécution du code généré (par exemple, pour faire correspondre une expression régulière lue au moment de l'exécution), car les programmes C ++ vanilla compilés statiquement ne peuvent utiliser l'interprétation que parce qu'ils n'ont pas de compilateur JIT intégré.
Jon Harrop
Note du futur: .NET prend en charge SIMD et ses amis depuis environ 2014, bien qu'il ne soit pas largement utilisé.
Luaan
9

Je sais que ce n'est pas ce que vous demandiez, mais C # est souvent plus rapide à écrire que C ++, ce qui est un gros bonus dans un environnement commercial.

Kramii
la source
2
Je dirais que c'est plus rapide la plupart du temps :)
Trap
8

C / C ++ peut être beaucoup plus performant dans les programmes où il y a soit de grands tableaux, soit des boucles / itérations lourdes sur des tableaux (de n'importe quelle taille). C'est la raison pour laquelle les graphiques sont généralement beaucoup plus rapides en C / C ++, car les opérations de tableau lourd sous-tendent presque toutes les opérations graphiques. .NET est notoirement lent dans les opérations d'indexation de tableaux en raison de toutes les vérifications de sécurité, et cela est particulièrement vrai pour les tableaux multidimensionnels (et, oui, les tableaux C # rectangulaires sont encore plus lents que les tableaux C # dentelés).

Les bonus de C / C ++ sont plus prononcés si vous vous en tenez directement aux pointeurs et évitez Boost std::vectoret autres conteneurs de haut niveau, ainsi que inlinetoutes les petites fonctions possibles. Utilisez des tableaux à l'ancienne autant que possible. Oui, vous aurez besoin de plus de lignes de code pour accomplir la même chose que vous avez fait en Java ou C # car vous évitez les conteneurs de haut niveau. Si vous avez besoin d'un tableau de taille dynamique, il vous suffit de vous rappeler de le coupler new T[]avec un correspondantdelete[] instruction (ou d'utiliserstd::unique_ptr) - le prix de la vitesse supplémentaire est que vous devez coder plus soigneusement. Mais en échange, vous pouvez vous débarrasser de la surcharge de la mémoire gérée / du garbage collector, qui peut facilement représenter 20% ou plus du temps d'exécution des programmes fortement orientés objet en Java et .NET, ainsi que ceux massivement gérés les coûts d'indexation des matrices de mémoire. Les applications C ++ peuvent également bénéficier de certains commutateurs de compilateur astucieux dans certains cas spécifiques.

Je suis un programmeur expert en C, C ++, Java et C #. J'ai récemment eu l'occasion rare d'implémenter exactement le même programme algorithmique dans les 3 dernières langues. Le programme a eu beaucoup d'opérations mathématiques et de tableaux multidimensionnels. J'ai fortement optimisé cela dans les 3 langues. Les résultats étaient typiques de ce que je vois normalement dans des comparaisons moins rigoureuses: Java était environ 1,3 fois plus rapide que C # (la plupart des machines virtuelles Java sont plus optimisées que le CLR), et la version du pointeur brut C ++ est arrivée environ 2,1 fois plus rapide que C #. Notez que le programme C # n'utilisait que du code sécurisé - je pense que vous pourriez aussi bien le coder en C ++ avant d'utiliser leunsafe mot clé.

De peur que quelqu'un pense que j'ai quelque chose contre C #, je terminerai en disant que C # est probablement mon langage préféré. C'est le langage de développement le plus logique, intuitif et rapide que j'ai rencontré jusqu'à présent. Je fais tout mon prototypage en C #. Le langage C # présente de nombreux petits avantages subtils par rapport à Java (oui, je sais que Microsoft a eu la chance de corriger de nombreuses lacunes de Java en entrant tardivement dans le jeu et en copiant sans doute Java). Un toast à la Calendarclasse de Java ? Si Microsoft consacre un effort réel à optimiser le CLR et le .NET JITter, C # pourrait sérieusement prendre le relais. Je suis honnêtement surpris qu'ils ne l'aient pas déjà fait - ils ont fait tellement de choses correctement dans le langage C #, pourquoi ne pas le suivre avec des optimisations de compilateur lourdes? Peut-être que si nous mendions tous.

Sauce spéciale
la source
3
"vous aurez juste besoin de vous rappeler de coupler votre new T[]avec un correspondant delete[]" - Non, vous ne le faites pas. Il std::unique_ptrfaut faire ça pour toi.
emlai
en supposant que vous avez écrit quelque chose dans les graphiques pourquoi écrire du code sûr en c #, avez-vous envisagé d'utiliser du code dangereux et de comparer à nouveau?.
user3800527
7

> D'après ce que j'ai entendu ...

Votre difficulté semble être de décider si ce que vous avez entendu est crédible, et cette difficulté ne fera que se répéter lorsque vous tenterez d'évaluer les réponses sur ce site.

Comment allez-vous décider si les choses que les gens disent ici sont plus ou moins crédibles que ce que vous avez entendu à l'origine?

Une façon serait de demander des preuves .

Lorsque quelqu'un prétend "qu'il existe des domaines dans lesquels C # s'avère plus rapide que C ++", demandez-lui pourquoi il dit que , demandez-lui de vous montrer des mesures, demandez-lui de vous montrer des programmes. Parfois, ils auront simplement fait une erreur. Parfois, vous découvrirez qu'ils expriment simplement une opinion plutôt que de partager quelque chose qu'ils peuvent montrer être vrai.

Souvent, les informations et les opinions seront mélangées dans ce que les gens prétendent, et vous devrez essayer de déterminer lequel est lequel. Par exemple, à partir des réponses de ce forum:

  • "Prenez les références sur http://shootout.alioth.debian.org/ avec beaucoup de scepticisme, car elles testent largement le code arithmétique, qui n'est probablement pas du tout similaire à votre code."

    Demandez-vous si vous comprenez vraiment ce que «ces codes arithmétiques largement testés» signifient, puis demandez-vous si l'auteur vous a réellement montré que sa prétention est vraie.

  • "C'est un test plutôt inutile, car cela dépend vraiment de la façon dont les programmes individuels ont été optimisés. J'ai réussi à accélérer certains d'entre eux de 4 à 6 fois ou plus, ce qui montre clairement que la comparaison entre les programmes non optimisés est plutôt idiot."

    Demandez-vous si l'auteur vous a réellement montré qu'il a réussi à "accélérer certains d'entre eux de 4 à 6 fois ou plus" - c'est une affirmation facile à faire!

Peter Mortensen
la source
Je ne pourrais pas être plus d'accord avec vous et c'est la raison pour laquelle j'ai demandé dans ce forum ... Après tout, les réponses doivent être quelque part, n'est-ce pas? :)
Piège
1
Oui. La réponse est "Cela dépend".
user49117
6

Pour les problèmes «embarrassants parallèles», lorsque j'utilise Intel TBB et OpenMP sur C ++, j'ai observé une augmentation de performances d'environ 10 fois par rapport à des problèmes similaires (mathématiques pures) effectués avec C # et TPL. SIMD est un domaine où C # ne peut pas rivaliser, mais j'ai également eu l'impression que TPL a une surcharge importante.

Cela dit, j'utilise uniquement C ++ pour les tâches critiques pour les performances où je sais que je serai en mesure de multithread et d'obtenir des résultats rapidement. Pour tout le reste, C # (et parfois F #) est très bien.

Dmitri Nesteruk
la source
5

C'est une question extrêmement vague sans véritables réponses définitives.

Par exemple; Je préfère jouer à des jeux 3D créés en C ++ qu'en C #, car les performances sont certainement bien meilleures. (Et je connais XNA, etc., mais cela ne se rapproche pas du vrai).

D'autre part, comme mentionné précédemment; vous devez développer dans un langage qui vous permet de faire ce que vous voulez rapidement, puis d'optimiser si nécessaire.

David l'homme
la source
4
Pourriez-vous citer quelques exemples? Jeux écrits en C # ce que vous avez trouvé lent
Karl
1
Même les exemples d'applications fournis avec l'installation semblaient lents.
David The Man
9
Le garbage collector est une énorme responsabilité dans la création de jeux avec C #, car il peut démarrer à tout moment, provoquant des pauses majeures. La gestion explicite de la mémoire devient plus facile pour le développement de jeux.
postfuturiste
3
La plupart des jeux modernes sont limités par le GPU. Pour de tels jeux, peu importe si la logique (exécutée sur le processeur) est 10% plus lente, ils sont toujours limités par le GPU et non par le CPU. Le garbage collector est un vrai problème, provoquant de courts blocages aléatoires si les allocations de mémoire ne sont pas bien réglées.
Michael Entin
2
@postfuturist: Ce n'est pas vrai sur PC; le garbage collector fait un si bon travail pour entrer et sortir que je n'ai jamais rencontré de problème avec. Cependant, sur XBox 360 et Zune / Windows 7-Phone, le garbage collector est pas presque aussi intelligent que sur PC; Je n'ai jamais écrit pour non plus, mais les gens qui m'ont dit que le ramasse-miettes est un énorme problème.
BlueRaja - Danny Pflughoeft
5

Les langages .NET peuvent être aussi rapides que le code C ++, voire plus rapides, mais le code C ++ aura un débit plus constant car le runtime .NET doit faire une pause pour GC , même s'il est très intelligent sur ses pauses.

Donc, si vous avez du code qui doit constamment s'exécuter rapidement sans aucune pause, .NET introduira une latence à un moment donné , même si vous êtes très prudent avec le GC d'exécution.

Florian Doyon
la source
6
-1: C'est en fait un mythe. Premièrement, la latence du C ++ idiomatique est en fait horrible et souvent bien pire que .NET car RAII provoque des avalanches de destructeurs lorsque de grandes structures de données tombent hors de portée alors que les GC modernes sont incrémentiels et .NET est même simultané. Deuxièmement, vous pouvez réellement supprimer complètement les pauses du GC sur .NET en n'allouant pas.
Jon Harrop
2
Si vous faites cela, vous devez alors renoncer à utiliser le BCL car la plupart des méthodes créent des objets transitoires.
Florian Doyon
5
C'est tout à fait vrai, ce n'est qu'en .net 4 que le GC a été rendu incrémentiel. Nous avons une grande application C # qui fait une pause de quelques secondes à la fois pour GC. Pour les applications essentielles aux performances, c'est un tueur.
Justin
5
Il y a une raison pour laquelle les programmes qui ont tendance à pousser le matériel ont tendance à utiliser C ++. Vous avez un contrôle plus précis lorsque vous en avez besoin. Les performances ne sont essentielles que lorsque vous poussez le système, sinon utilisez C # ou Java pour vous faire gagner du temps.
VoronoiPotato
4
si vous ne pouvez pas gérer le comportement du cache, vous ne pouvez pas battre le code c ++ optimisé. Un échec de cache de L1 à la mémoire principale pourrait ralentir votre fonctionnement 100 fois.
DAG
4

En théorie, pour une application de type serveur de longue durée, un langage compilé JIT peut devenir beaucoup plus rapide qu'un équivalent compilé en mode natif. Étant donné que le langage compilé JIT est généralement d'abord compilé dans un langage intermédiaire de bas niveau, vous pouvez de toute façon effectuer de nombreuses optimisations de haut niveau au moment de la compilation. Le gros avantage est que le JIT peut continuer à recompiler des sections de code à la volée car il obtient de plus en plus de données sur la façon dont l'application est utilisée. Il peut organiser les chemins de code les plus courants pour permettre à la prédiction de branchement de réussir aussi souvent que possible. Il peut réorganiser des blocs de code séparés qui sont souvent appelés ensemble pour les garder tous les deux dans le cache. Il peut consacrer plus d'efforts à l'optimisation des boucles internes.

Je doute que cela soit fait par .NET ou l'un des JRE, mais cela faisait l'objet de recherches lorsque j'étais à l'université, il n'est donc pas déraisonnable de penser que ce genre de choses pourrait se retrouver dans le monde réel à un moment donné prochainement. .

Éclipse
la source
4

Les applications qui nécessitent un accès intensif à la mémoire, par exemple. la manipulation d'images est généralement mieux écrite en environnement non managé (C ++) que managée (C #). Les boucles internes optimisées avec l'arithmétique des pointeurs sont beaucoup plus faciles à contrôler en C ++. En C #, vous devrez peut-être recourir à du code non sécurisé pour obtenir même les mêmes performances.

Kalle
la source
4

J'ai testé vectoren équivalent C ++ et C # - Listet des tableaux 2d simples.

J'utilise les éditions Visual C # / C ++ 2010 Express. Les deux projets sont de simples applications console, je les ai testées en mode de sortie et de débogage standard (pas de paramètres personnalisés). Les listes C # s'exécutent plus rapidement sur mon PC, l'initialisation des tableaux est également plus rapide en C #, les opérations mathématiques sont plus lentes.

J'utilise Intel Core2Duo [email protected], C # - .NET 4.0.

Je sais que l'implémentation vectorielle est différente de la liste C #, mais je voulais juste tester les collections que j'utiliserais pour stocker mes objets (et pouvoir utiliser l'accesseur d'index).

Bien sûr, vous devez effacer la mémoire (disons pour chaque utilisation de new), mais je voulais garder le code simple.

Test vectoriel C ++ :

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

Test de liste C #:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C ++ - tableau:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

C # - tableau:

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

Heure: (Release / Debug)

C ++

  • Init de tableau 600/606 ms,
  • Remplissage du tableau 200/270 ms,
  • 1sec / 13sec vecteur init & fill.

(Oui, 13 secondes, j'ai toujours des problèmes avec les listes / vecteurs en mode débogage.)

C #:

  • Init de tableau 20/20 ms,
  • Remplissage de matrice 403/440 ms,
  • 710/742 ms liste init & fill.
Wiory
la source
1
J'aimerais voir l'accesseur d'index dans std :: list. Quoi qu'il en soit, cela prend 37 secondes avec la liste, le mode de libération. Sortie sans débogage: liste 3s, vecteur 0,3 s. Probablement un problème de déréférencement ou qc. Échantillon: nopaste.pl/12fb
Wiory
2
Pour des mesures plus précises, vous ne devriez pas utiliser System.DateTime.Now, mais plutôt la classe Chronomètre .
Sam
4
Une partie de la raison pour laquelle vous obtenez des temps de remplissage si lents pour le vecteur en C ++ est que vous utilisez push_back. Cela a été démontré sur de nombreux postes pour être plus lent que l'utilisation de la méthode ou de l'opérateur []. Pour utiliser l'une de ces méthodes, vous devez utiliser la méthode de redimensionnement ou de réservation. De plus, la raison pour laquelle votre initialisation prend si longtemps pour le cas du vecteur c ++ est que vous forcez un opérateur de copie ou d'affectation [pas sûr lequel dans ce cas) à initialiser votre vecteur c ++. Pour le tableau en c ++, il existe un algorithme qui utilise 2 nouveaux appels plutôt que 5001 et qui est également plus rapide à répéter.
Zachary Kraus
5
Je pense que vous n'avez pas fait le c ++ de manière appropriée. Juste un coup d'œil et trouvé tant de problèmes. Par exemple, vector <vector <double>> myList = vector <vector <double>> ()
DAG
2
Sensationnel. Je ne sais pas quelles conclusions on peut tirer de la comparaison des listes par rapport aux tableaux redimensionnables, mais si vous allez utiliser des vecteurs comme celui-ci, vous voudrez en savoir plus sur reserve (), mon ami, reserve ().
U007D
3

En fait ça dépend. Si le code d'octet est traduit en code machine (et pas seulement JIT) (je veux dire si vous exécutez le programme) et si votre programme utilise de nombreuses allocations / désallocations, cela pourrait être plus rapide car l' algorithme GC n'a besoin que d'un passage (théoriquement) dans toute la mémoire une fois, mais les appels normaux malloc / realloc / free C / C ++ entraînent une surcharge pour chaque appel (surcharge d'appel, surcharge de structure de données, échecs de cache;)).

Il est donc théoriquement possible (également pour d'autres langages GC).

Je ne vois pas vraiment l'inconvénient extrême de ne pas pouvoir utiliser la métaprogrammation avec C # pour la plupart des applications, car la plupart des programmeurs ne l'utilisent pas de toute façon.

Un autre gros avantage est que le SQL, comme l ' "extension" LINQ , offre au compilateur la possibilité d'optimiser les appels aux bases de données (en d'autres termes, le compilateur pourrait compiler le LINQ entier dans un binaire "blob" où les fonctions appelées sont en ligne ou pour votre utilisation optimisée, mais je spécule ici).

Quonux
la source
1
Tout développeur C ++ approprié ne rencontrera pas les problèmes que vous décrivez. Seuls les mauvais programmeurs C qui ont décidé de gifler les classes sur leurs programmes et de l'appeler C ++ ont ces problèmes.
Plus clair le
1
pour l'amour des dieux, cela a 8 ans, OMFGz
Quonux
n'hésitez pas à donner une meilleure réponse plus à jour
Quonux
2

Je suppose qu'il y a des applications écrites en C # qui s'exécutent rapidement, ainsi que d'autres applications écrites en C ++ qui s'exécutent rapidement (enfin C ++ juste plus ancien ... et prennent UNIX aussi ...)
- la question est en effet - quelle est cette chose, les utilisateurs et les développeurs se plaignent de ...
Eh bien, à mon humble avis, dans le cas de C #, nous avons une interface utilisateur très confortable, une très belle hiérarchie de bibliothèques et tout le système d'interface de CLI. Dans le cas de C ++, nous avons des modèles, ATL, COM, MFC et tout le code déjà écrit et en cours d'exécution comme OpenGL, DirectX et ainsi de suite ... en une seconde - bang! c'est coincé).
Pour écrire du code en C # très simple et rapide (sans oublier cela augmente également les risques d'erreurs. En cas de C ++, les développeurs se plaignent de fuites de mémoire, - signifie des écrasements, des appels entre DLL, ainsi que de "l'enfer des DLL" - problème avec support et remplacement des bibliothèques par des plus récentes ...
Je pense que plus vous aurez de compétences dans le langage de programmation, plus la qualité (et la vitesse) caractérisera votre logiciel.

bgee
la source
2

Je dirais les choses ainsi: les programmeurs qui écrivent du code plus rapidement sont ceux qui sont les mieux informés de ce qui fait que les machines actuelles vont vite, et accessoirement ce sont aussi ceux qui utilisent un outil approprié qui permet un bas niveau précis et déterministe techniques d'optimisation. Pour ces raisons, ces personnes sont celles qui utilisent C / C ++ plutôt que C #. J'irais jusqu'à affirmer cela comme un fait.

Johan Boulé
la source
Minecraft codé par Notch pour être assez rapide compte tenu de la quantité de données qu'il manipule. En outre, il l'a codé principalement à lui seul dans un laps de temps relativement court, ce qui aurait été pratiquement impossible en C ++. Cependant, je suis d'accord avec les techniques d'optimisation - si vous avez 10 fois plus de temps de développement pour que votre code s'exécute deux fois plus vite, cela en vaut probablement la peine.
Bill K
2

Si je ne me trompe pas, les modèles C # sont déterminés lors de l'exécution. Cela doit être plus lent que les modèles de temps de compilation de C ++.

Et quand vous prenez en compte toutes les autres optimisations au moment de la compilation mentionnées par tant d'autres, ainsi que le manque de sécurité qui signifie, en effet, plus de vitesse ...

Je dirais que C ++ est le choix évident en termes de vitesse brute et de consommation minimale de mémoire. Mais cela se traduit également par plus de temps à développer le code et à vous assurer que vous ne perdez pas de mémoire ou ne provoquez aucune exception de pointeur nul.

Verdict:

  • C #: développement plus rapide, exécution plus lente

  • C ++: développement lent, exécution plus rapide.

HumbleWebDev
la source
1

Cela dépend vraiment de ce que vous essayez d'accomplir dans votre code. J'ai entendu dire que c'est juste une légende urbaine qu'il y a une différence de performances entre VB.NET, C # et C ++ managé. Cependant, j'ai trouvé, au moins dans les comparaisons de chaînes, que C ++ géré bat le pantalon hors de C #, qui à son tour bat le pantalon hors de VB.NET.

Je n'ai en aucun cas fait de comparaisons exhaustives en termes de complexité algorithmique entre les langues. J'utilise également les paramètres par défaut dans chacune des langues. Dans VB.NET, j'utilise des paramètres pour exiger la déclaration de variables, etc. Voici le code que j'utilise pour le C ++ managé: (Comme vous pouvez le voir, ce code est assez simple). J'exécute la même chose dans les autres langues de Visual Studio 2013 avec .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}
Charles Owen
la source
1

Il existe quelques différences majeures entre C # et C ++ sur l'aspect performances:

  • C # est basé sur GC / tas. L'allocation et le GC lui-même sont des frais généraux comme la non localité de l'accès à la mémoire
  • Les optimiseurs C ++ sont devenus très bons au fil des ans. Les compilateurs JIT ne peuvent pas atteindre le même niveau car ils ont seulement un temps de compilation limité et ne voient pas la portée globale

Outre que la compétence du programmeur joue également un rôle. J'ai vu un mauvais code C ++ où les classes étaient passées par valeur comme argument partout. Vous pouvez réellement aggraver les performances en C ++ si vous ne savez pas ce que vous faites.

gast128
la source
0

> Après tout, les réponses doivent être quelque part, non? :)

Umm, non.

Comme plusieurs réponses l'ont noté, la question est sous-spécifiée de manière à inviter des questions à répondre, pas des réponses. Pour prendre une seule façon:

Et puis quels programmes? Quelle machine? Quel OS? Quel ensemble de données?

Peter Mortensen
la source
Je suis complètement d'accord. Je me demande pourquoi les gens attendent une réponse précise (63,5%), lorsqu'ils posent une question générale. Je ne pense pas qu'il n'y ait pas de réponse générale à ce genre de question.
appelez-moi Steve
@callmesteve: Je sais ce que vous voulez dire, mais votre dernière phrase devrait ressembler à des clous sur un tableau noir pour n'importe quel programmeur.
Wouter van Nifterick
1
Cela ne semble pas répondre à la question et se lit plus comme un commentaire ou une diatribe.
Tas
-13

Inspiré par cela, j'ai fait un test rapide avec 60% des instructions communes nécessaires dans la plupart des programmes.

Voici le code C #:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

Le tableau de chaînes et l'arraylist sont utilisés à dessein pour inclure ces instructions.

Voici le code c ++:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

La taille du fichier d'entrée que j'ai utilisé était de 40 Ko.

Et voici le résultat -

  • Le code C ++ a fonctionné en 9 secondes.
  • Code C #: 4 secondes !!!

Oh, mais c'était sur Linux ... Avec C # fonctionnant sur Mono ... Et C ++ avec g ++.

OK, voici ce que j'ai obtenu sous Windows - Visual Studio 2003 :

  • Le code C # a fonctionné en 9 secondes.
  • Code C ++ - horrible 370 secondes !!!
rks
la source
7
Vous utilisez différentes structures de données et code de bibliothèque là-bas, bien que "370 secondes" indique quelque chose d'horrible - vous ne le lancez pas par hasard dans le débogueur, n'est-ce pas? Je soupçonne que les performances de la bibliothèque CSV que vous utilisez sont plus intéressantes que les performances de la langue que vous utilisez. Je remettrais en question l'utilisation d'un vecteur dans ce contexte et les optimisations que vous avez utilisées. De plus, il est bien connu que les iostreams (en particulier, le "monfichier << * j <<", ";") sont beaucoup plus lents que les autres méthodes d'écriture dans le fichier, pour au moins certaines implémentations courantes.
Arafangion
6
Enfin, vous travaillez davantage dans la version C ++. (Pourquoi effacez-vous csvColumn, csvElement et csvLines?)
Arafangion
2
Chaque itération de la boucle while va détruire et reconstruire un std :: istream et un std :: vector et une std :: string. Le corps while sort de la portée à chaque itération, toutes ces variables à l'intérieur de la portée while vont détruire et construire à chaque itération.
doug65536
1
de l'apparence de la lecture de votre code c ++ que vous essayez de copier d'un fichier vers un autre fichier. Au lieu d'utiliser les interactions complexes entre les flux de fichiers, les chaînes, les vecteurs et les flux de chaînes, vous auriez pu simplement copier le flux de fichiers d'entrée dans le flux de fichiers de sortie. Cela aurait permis d'économiser beaucoup de temps et de mémoire.
Zachary Kraus
2
pour faire des tests de vitesse, tester des choses dans la mémoire, n'obtenez pas sur le disque IO, à moins que vos tests sur les derniers SSD et son dédié à votre application de performance. Comme les ordinateurs écrivent constamment sur le disque, même si vous ne touchez pas le clavier.
user3800527