97 votes

C # vs C - Grande différence de performance

Je suis la recherche massive des écarts de rendement entre un code similaire dans C anc C#.

Le code C est:

#include <stdio.h>
#include <time.h>
#include <math.h>

main()
{
    int i;
    double root;

    clock_t start = clock();
    for (i = 0 ; i <= 100000000; i++){
    	root = sqrt(i);
    }
    printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);	

}

Et le C# (application console) est:

using System;
using System.Collections.Generic;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            DateTime startTime = DateTime.Now;
            double root;
            for (int i = 0; i <= 100000000; i++)
            {
                root = Math.Sqrt(i);
            }
            TimeSpan runTime = DateTime.Now - startTime;
            Console.WriteLine("Time elapsed: " + Convert.ToString(runTime.TotalMilliseconds/1000));
        }
    }
}

Avec le code ci-dessus, le C# est terminée dans 0.328125 secondes (version) et le C prend 11.14 secondes pour s'exécuter.

La c est compilé en un exécutable windows avec mingw.

J'ai toujours été sous l'hypothèse que le C/C++ ont été les plus rapides ou au moins comparables à C#.net. Qu'est-ce exactement est à l'origine de la C pour exécuter plus de 30 fois plus lent?

EDIT: Il semble que le C# optimizer a été de retirer la racine comme il n'était pas utilisé. J'ai changé la racine de l'assignation à la racine += et imprimer le total à la fin. J'ai également compilé en C à l'aide de cl.exe avec l' /O2 indicateur de vitesse max.

Les résultats sont les suivants: De 3,75 secondes pour le C 2.61 secondes pour le C#

La C est encore plus long, mais c'est acceptable

171voto

jalf Points 142628

Vous devez être en le comparant les versions de débogage. Je viens de compiler votre code en C, et a obtenu

Time elapsed: 0.000000

Si vous n'activez pas les optimisations, toute analyse comparative de vous faire est complètement inutile. (Et si vous n'activer les optimisations, la boucle est optimisé loin. Si votre banc de code est erroné. Vous avez besoin de forcer pour exécuter la boucle, généralement en additionnant le résultat ou similaire, et l'impression à la fin)

Il semble que ce que vous êtes en mesure de fondamentalement "le compilateur insère le débogage plus généraux". Et s'avère que la réponse est C. Mais cela ne nous dit pas quel programme est le plus rapide. Parce que quand vous voulez de la vitesse, vous devez activer les optimisations.

Par le chemin, vous allez vous sauver beaucoup de maux de tête dans le long terme, si vous abandonner toute notion de langages "plus vite" que les uns et les autres. C# pas de plus a une vitesse que l'anglais.

Il y a certaines choses dans le langage C qui serait efficace, même dans un naïf non-optimisation du compilateur, et il en est d'autres qui s'appuie fortement sur un compilateur d'optimiser tout de suite. Et bien sûr, il en va de même pour le C# ou en toute autre langue.

La vitesse d'exécution est déterminé par:

  • la plate-forme, vous êtes en cours d'exécution sur (système d'exploitation, matériel, d'autres logiciels en cours d'exécution sur le système)
  • le compilateur
  • votre code source

Un bon compilateur C# aura un rendement efficace du code. Un mauvais C compilateur va générer lente code. Que penser d'un compilateur C qui a généré le code C#, vous pouvez ensuite exécuter par le biais d'un compilateur C#? Comment rapide que de courir? Les langues n'ont pas une vitesse. Votre code ne.

122voto

Hans Passant Points 475940

Je vais être bref, il est d'ores et déjà répondu. C# a le grand avantage d'avoir un sens bien défini à virgule flottante modèle. Qui arrive juste à correspondre à la native mode de fonctionnement de la FPU et le jeu d'instructions SSE sur les processeurs x86 et x64. Pas un hasard. La Gigue compile les Mathématiques.Sqrt() de quelques inline instructions.

Natif C/C++ est aux prises avec des années de rétro-compatibilité. L' /fp:précis, /fp:rapide et /fp:des options de compilation sont les plus visibles. En conséquence, il doit appeler une fonction CRT qui implémente sqrt() et des contrôles sélectionnés à virgule flottante options pour ajuster le résultat. C'est lent.

63voto

Brann Points 9983

Puisque vous n'utilisez jamais 'root', le compilateur a peut-être supprimé l'appel pour optimiser votre méthode.

Vous pouvez essayer d'accumuler les valeurs de racine carrée dans un accumulateur, de l'imprimer à la fin de la méthode et de voir ce qui se passe.

Edit: voir la réponse de Jalf ci-dessous

60voto

Richard Points 573

Je suis une C++ et un développeur C#. J'ai développé des applications C# depuis la première version bêta de l' .NET framework et j'ai eu plus de 20 ans d'expérience dans le développement d'applications C++. Tout d'abord, le code C# ne sera JAMAIS plus vite qu'une application C++, mais je ne vais pas passer par une longue discussion sur le code managé, comment il fonctionne, l'inter-op de la couche, la gestion de la mémoire interne, le système de type dynamique et le garbage collector. Néanmoins, permettez-moi de continuer en disant que le les repères figurant ici tous produire des résultats INCORRECTS.

Laissez-moi vous expliquer: La première chose que nous devons considérer est le compilateur JIT pour C# (.NET Framework 4). Maintenant, l'équipe produit du code natif pour le CPU à l'aide de différents algorithmes d'optimisation (qui ont tendance à être plus agressifs que la valeur par défaut C++ optimiseur fourni avec Visual Studio) et le jeu d'instructions utilisés par les .NET compilateur JIT sont plus près de la réflexion de l'effectif de la CPU sur la machine de sorte que certaines substitutions dans le code de l'ordinateur pourrait être fait pour réduire les temps de cycle et d'améliorer le taux de succès dans le PROCESSEUR pipeline de cache et de produire d'autres hyper-threading optimisations telles que la réorganisation de l'instruction et des améliorations relatives à la direction de la prévision.

Ce que cela signifie est que si vous compilez votre application C++ en utilisant la bonne pararmeters pour la version RELEASE (pas la version DEBUG) puis votre application C++ peut exécuter plus lentement que le correspondant de C# ou .NET en fonction de l'application. Lorsque vous spécifiez les propriétés du projet sur votre application C++, assurez-vous que vous activez l'option "optimisation" et "favoriser code rapide". Si vous avez un ordinateur 64 bits, vous DEVEZ spécifier à générer x64 comme la plate-forme cible, sinon, votre code sera exécuté par une conversion de la sous-couche (WOW64) qui permettra de réduire considérablement les performances.

Une fois que vous effectuez la bonne optimisations du compilateur, je reçois .72 secondes pour l'application C++ et 1,16 secondes pour l'application en C# (à la fois en version release). Depuis l'application en C# est très basique et alloue de la mémoire utilisée dans la boucle sur la pile et non pas sur le tas, c'est effectivement beaucoup mieux qu'une application réelle impliqués dans des objets lourds, de calculs et avec de plus grands ensembles de données. Donc, les chiffres fournis sont optimistes chiffres biaisés en faveur de C# et de la .NET framework. Même avec ce biais, l'application C++ termine en un peu plus de la moitié du temps que l'équivalent application en C#. Gardez à l'esprit que le compilateur C++ de Microsoft, j'ai utilisé n'a pas le droit de pipeline et l'hyperthreading optimisations (à l'aide de WinDBG pour afficher les instructions de montage).

Maintenant, si nous utilisons le compilateur Intel (qui est une industrie de secret pour générer des applications de haute performance sur AMD/Intel-processeurs), le même code s'exécute dans .54 secondes pour le C++ exécutable vs le .72 secondes à l'aide de Microsoft Visual Studio 2010. Donc en fin de compte, les résultats finaux sont .54 secondes pour C++ et 1,16 secondes pour C#. De sorte que le code produit par le .NET compilateur JIT prend 214% fois plus longtemps que le C++ exécutable. La plupart du temps passé dans la .54 secondes a été dans l'obtention de l'heure du système et non pas à l'intérieur de la boucle elle-même!

Ce qui manque aussi dans les statistiques est le démarrage et le nettoyage des temps qui ne sont pas inclus dans les horaires. Des applications C# ont tendance à passer beaucoup plus de temps au démarrage et lors de la résiliation que des applications C++. La raison derrière cela est compliqué et a à voir avec l' .NET runtime code des routines de validation et de la gestion de la mémoire sous-système qui effectue beaucoup de travail au début (et par conséquent, à la fin du programme afin d'optimiser les allocations de mémoire et le garbage collector.

Lors de la mesure de la performance de C++ et de .NET IL, il est important de regarder le code assembleur pour s'assurer que TOUS les calculs sont là. Ce que j'ai trouvé est que, sans mettre un peu de code supplémentaire en C#, la plupart du code dans les exemples ci-dessus ont été effectivement retiré de la binaire. Ce fut également le cas avec C++ lorsque vous avez utilisé une forme plus agressive de l'optimiseur tel que celui qui est fourni avec le compilateur Intel C++. Les résultats que j'ai fournis ci-dessus sont corrects à 100% et validé au niveau de l'assemblage.

Le principal problème avec beaucoup de forums sur internet que beaucoup de débutants écouter Microsoft marketing de la propagande sans la compréhension de la technologie et de faire de fausses déclarations que le C# est plus rapide que le C++. La revendication est que, en théorie, le C# est plus rapide que le C++ parce que le compilateur JIT peut optimiser le code pour le PROCESSEUR. Le problème avec cette théorie est que beaucoup de la plomberie qui existe dans le .NET framework qui ralentit la performance; de plomberie qui n'existe pas en C++ de l'application. En outre, un développeur expérimenté saura le droit compilateur à utiliser pour la plate-forme donnée et utiliser les indicateurs lors de la compilation de l'application. Sur Linux ou plates-formes open source, ce n'est pas un problème parce que vous pouvez distribuer votre source et de créer des scripts d'installation que de compiler le code à l'aide de l'optimisation approprié. Sur les fenêtres ou à code source fermé plate-forme, vous aurez à distribuer plusieurs exécutables, chacun avec des optimisations spécifiques. Les binaires pour windows qui seront déployées sont basés sur le PROCESSEUR détecté par le programme d'installation msi (à l'aide d'actions personnalisées).

10voto

Neil N Points 14566

Ma première hypothèse est une optimisation du compilateur, car vous n'utilisez jamais root. Vous venez de l'affecter, puis de l'écraser encore et encore.

Edit: putain, battre par 9 secondes!

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