Pourquoi le C est-il si rapide et pourquoi les autres langages ne sont-ils pas aussi rapides ou plus rapides? [fermé]


209

En écoutant le podcast StackOverflow, le jab continue de dire que les "vrais programmeurs" écrivent en C, et que C est tellement plus rapide parce qu'il est "proche de la machine". Laissant l'ancienne affirmation pour un autre poste, quelle est la particularité de C qui lui permet d'être plus rapide que les autres langues? Ou en d'autres termes: qu'est-ce qui empêche les autres langages de pouvoir compiler en binaire qui s'exécute tout aussi vite que C?


6
Pouvez-vous indiquer quelle émission en particulier en a parlé? J'adorerais l'entendre.
Giovanni Galbo

2
Vraiment surpris de voir à quel point cette question est mal répondue (la plupart des réponses ignorent les différences fondamentales entre les langues compilées et interprétées, etc., je connais JIT yada yada yada), et combien de personnes prennent position pour défendre leur langue préférée (FORTRAN boy needs prendre une pilule).
Tim Ring le

N'oubliez pas le langage d'assemblage. Rien n'est plus rapide ou plus compact que les ex assemblés. L'assemblage est presque pur binaire, c'est donc sans parti pris le langage le plus rapide.
KKZiomek

3
C est le plus rapide parce que c'est la vitesse de la lumière et la relativité?
Rencontrez Taraviya le

Il est évidemment faux que C soit le langage de programmation le plus rapide. Aucun langage de programmation d'aucune sorte ne se rapproche de la vitesse de FORTH. FORTH est utilisé pour déclencher des bombes nucléaires, c'est le langage de programmation sur la plupart des satellites, le langage de programmation principal de la Station spatiale internationale ainsi qu'au CERN et à ITER. Je comparais la vitesse entre Microsoft C (différentes versions) et FORTH. YAWN to C ...
Scoobeedo Cool

Réponses:


200

Il n'y a pas grand-chose de spécial à propos de C. C'est l'une des raisons pour lesquelles c'est rapide.

Langages plus récents qui prennent en charge la récupération de place , la frappe dynamique et d'autres fonctionnalités qui facilitent l'écriture de programmes par le programmeur.

Le hic, c'est qu'il y a des frais supplémentaires de traitement qui dégraderont les performances de l'application. C n'a rien de tout cela, ce qui signifie qu'il n'y a pas de surcharge, mais cela signifie que le programmeur doit être en mesure d'allouer de la mémoire et de les libérer pour éviter les fuites de mémoire , et doit gérer le typage statique des variables.

Cela dit, de nombreux langages et plates-formes, tels que Java (avec sa machine virtuelle Java ) et .NET (avec son Common Language Runtime) ont amélioré les performances au fil des ans grâce à des avantages tels que la compilation juste à temps qui produit du code machine natif à partir de bytecode pour obtenir de meilleures performances.


3
la récupération de place peut être plus rapide que la gestion manuelle de la mémoire (pour les programmes de courte durée et / ou beaucoup de mémoire). GC permet une allocation simple et rapide, et le programme ne passe pas de temps à désallouer les choses.
Kornel

2
Les programmes C allouent et désallouent généralement la mémoire selon les besoins. C'est inefficace. Une bonne machine virtuelle allouera et désallouera en gros morceaux, générant de gros gains de performances dans de nombreux cas.
skaffman

61
Rien n'empêche un programme C d'effectuer la même allocation en morceaux et la même collecte de déchets, à part qu'il est "difficile".
éphémère

Très bien dit, mais comme Rob Allen l'a dit, C fournit également moins d'abstraction que Java ou .NET, résultant en moins de traduction (ce qui est moins vrai de nos jours en raison de la compilation juste à temps (JIT) comme vous l'avez dit)
Gab Royer

5
porneL, la gestion manuelle et les allocations judicieuses surpasseront toujours n'importe quel système GC lorsqu'il est utilisé correctement et beaucoup d'attention est accordée, vous avez une connaissance absolue de vos modèles d'utilisation, le GC non, plus les systèmes GC ajoutent des frais généraux
Ion Todirel

89

Il y a un compromis que les concepteurs C ont fait. C'est-à-dire qu'ils ont décidé de mettre la vitesse au-dessus de la sécurité. C ne sera pas

  • Vérifier les limites de l'index du tableau
  • Vérifier les valeurs des variables non initialisées
  • Vérifiez les fuites de mémoire
  • Vérifier la déréférence du pointeur nul

Lorsque vous indexez dans un tableau, en Java, il faut un appel de méthode dans la machine virtuelle, une vérification des liens et d'autres vérifications d'intégrité. C'est valable et tout à fait correct , car cela ajoute de la sécurité là où c'est dû. Mais en C, même des choses assez banales ne sont pas mises en sécurité. Par exemple, C ne nécessite pas memcpy pour vérifier si les régions à copier se chevauchent. Il n'est pas conçu comme un langage pour programmer une application de grande entreprise.

Mais ces décisions de conception sont pas des bugs dans le langage C . Ils sont de par leur conception, car ils permettent aux compilateurs et aux rédacteurs de bibliothèques de tirer le maximum de performances de l'ordinateur. Voici l'esprit de C comment le document de justification C l' explique:

Le code C peut être non portable. Bien qu'il se soit efforcé de donner aux programmeurs la possibilité d'écrire des programmes vraiment portables, le Comité n'a pas voulu forcer les programmeurs à écrire de manière portable, pour empêcher l'utilisation de C comme `` assembleur de haut niveau '': la capacité d'écrire spécifique à la machine le code est l'une des forces de C.

Gardez l'esprit de C. Le Comité a gardé comme objectif majeur de préserver l'esprit traditionnel de C. Il y a de nombreuses facettes de l'esprit de C, mais l'essence est un sentiment communautaire des principes sous-jacents sur lesquels le langage C est basé. Certaines des facettes de l'esprit de C peuvent être résumées dans des phrases comme

  • Faites confiance au programmeur.
  • N'empêchez pas le programmeur de faire ce qui doit être fait.
  • Gardez la langue petite et simple.
  • Fournissez une seule façon de faire une opération.
  • Faites vite, même s'il n'est pas garanti d'être portable.

Le dernier proverbe a besoin d'une petite explication. Le potentiel de génération de code efficace est l'une des forces les plus importantes de C.Pour garantir qu'aucune explosion de code ne se produise pour ce qui semble être une opération très simple, de nombreuses opérations sont définies comme la façon dont le matériel de la machine cible le fait plutôt que par une règle abstraite générale. Un exemple de cette volonté de vivre avec ce que fait la machine peut être vu dans les règles qui gouvernent l'élargissement des objets char pour une utilisation dans les expressions: si les valeurs des objets char s'élargissent aux quantités signées ou non signées dépendent généralement de l'octet qui est le plus efficace sur la machine cible.


51
C vérifie le pointeur nul deref en plantant violemment :-). Il vérifie également occasionnellement les index de tableau hors plage et les variables non initialisées en vissant vos trames de pile et vos données. Malheureusement, il les vérifie au moment de l'exécution.
paxdiablo

18
Je ne dirais pas que C n'est pas sûr, ce qui ressemble à ce que vous faites allusion. Cela suppose que vous n'êtes pas un idiot. Si vous pointez une arme vers le bas et que vous vous tirez une balle dans le pied, C se fera un plaisir de vous obliger et vous laissera faire cela car cela suppose que vous êtes plus intelligent qu'il ne l'est. Ce n'est pas nécessairement une mauvaise chose.
Bob Somers

19
@Bob: Exactement. Dire C n'est pas sûr parce qu'il vous permet de faire des choses dangereuses, c'est comme dire qu'une voiture n'est pas sûre car elle vous permettra de conduire d'une falaise. C est aussi sûr que la personne qui conduit (mais il y a beaucoup de conducteurs dangereux).
Robert Gamble

5
Bob, faire des bugs comme des dépassements de tampon ne signifie pas que tu es un idiot. Cela signifie simplement que vous êtes toujours humain. Je me rends compte que C et C ++ n'est pas mauvais (je les aime beaucoup).
Johannes Schaub - litb

4
@ JohannesSchaub-litb C est parfait pour la programmation d'applications à grande échelle. Si on a du mal à faire des projets plus gros qu'un bonjour, alors le problème est avec le programmeur, pas avec la langue ...

75

Si vous passez un mois à construire quelque chose en C qui s'exécute en 0,05 seconde, et que je passe une journée à écrire la même chose en Java, et cela s'exécute en 0,10 seconde, alors C est-il vraiment plus rapide?

Mais pour répondre à votre question, un code C bien écrit s'exécutera généralement plus rapidement que du code bien écrit dans d'autres langues car une partie de l'écriture "bien" du code C comprend la réalisation d'optimisations manuelles à un niveau proche de la machine.

Bien que les compilateurs soient en effet très intelligents, ils ne sont pas encore capables de créer de manière créative du code qui rivalise avec les algorithmes massés à la main (en supposant que les "mains" appartiennent à un bon programmeur C).

Éditer:

Beaucoup de commentaires vont dans le sens de «j'écris en C et je ne pense pas aux optimisations».

Mais pour prendre un exemple spécifique de ce post :

En Delphi, je pourrais écrire ceci:

function RemoveAllAFromB(a, b: string): string;
var
  before, after :string;
begin
  Result := b;
  if 0 < Pos(a,b) then begin
    before := Copy(b,1,Pos(a,b)-Length(a));
    after := Copy(b,Pos(a,b)+Length(a),Length(b));
    Result := before + after;
    Result := RemoveAllAFromB(a,Result);  //recursive
  end;
end;

et en CI écrivez ceci:

char *s1, *s2, *result; /* original strings and the result string */
int len1, len2; /* lengths of the strings */
for (i = 0; i < len1; i++) {
   for (j = 0; j < len2; j++) {
     if (s1[i] == s2[j]) {
       break;
     }
   }
   if (j == len2) {  /* s1[i] is not found in s2 */
     *result = s1[i]; 
     result++; /* assuming your result array is long enough */
   }
}

Mais combien d'optimisations y a-t-il dans la version C? Nous prenons beaucoup de décisions sur l'implémentation auxquelles je ne pense pas dans la version Delphi. Comment une chaîne est-elle implémentée? Dans Delphi, je ne le vois pas. En C, j'ai décidé que ce sera un pointeur vers un tableau d'entiers ASCII, que nous appelons des caractères. En C, nous testons l'existence des personnages un par un. En Delphi, j'utilise Pos.

Et ce n'est qu'un petit exemple. Dans un grand programme, un programmeur C doit prendre ce type de décisions de bas niveau avec quelques lignes de code. Il s'ajoute à un exécutable fabriqué à la main et optimisé à la main.


46
Pour être juste cependant, il n'y a pas grand-chose qui prendrait un mois en C qui ne prendrait qu'une journée en Java qui ne prend que 0,05 seconde pour s'exécuter (c'est-à-dire un petit programme).
dreamlax

13
J'ai programmé en C pendant des années et je n'ai presque jamais à faire les optimisations que vous indiquez. J'ai porté un certain nombre de programmes en C (principalement de Perl) et je constate généralement une augmentation de la vitesse 10x plus et une réduction significative de l'utilisation de la mémoire sans aucune optimisation codée à la main.
Robert Gamble

1
Bien sûr, certaines choses peuvent prendre beaucoup plus de temps à programmer en C en raison du manque d'installations existantes, c'est donc un compromis entre les performances de l'ordinateur et les performances du programmeur (entre autres), c'est pourquoi nous ne programmons pas tout en C.
Robert Gamble

4
J'ai créé des programmes C ++ qui traitent des milliers de lignes de données en moins de temps que les programmes Java ou .NET peuvent démarrer. C'est l'une des frustrations que j'ai avec les langues les plus modernes. C est idéal pour les programmes lean qui nécessitent des exigences d'exécution minimales. PowerBasic est également idéal pour cela.
bruceatk

35
Vous dites qu'un programme qui prend un mois en C et est deux fois plus rapide qu'un programme écrit en Java qui ne prend qu'un jour pour écrire ne vaut pas la peine? Et si ce programme devait être exécuté 500 000 000+ fois par jour? Être deux fois plus rapide est incroyablement significatif. S'il fonctionne sur des milliers ou des millions de processeurs, les économies de coûts du mois de développement supplémentaire pour atteindre deux fois les performances seront énormes. Fondamentalement, vous devez connaître / comprendre l'ampleur de votre déploiement avant de choisir la plate-forme de développement.
nicerobot

49

Je ne l'ai pas déjà, donc je vais le dire: C a tendance à être plus rapide parce que presque tout est écrit ailleurs dans C .

Java est construit sur C, Python est construit sur C (ou Java, ou .NET, etc.), Perl est, etc. Le système d'exploitation est écrit en C, les machines virtuelles sont écrites en C, les compilateurs sont écrits en C, les interprètes sont écrits en C. Certaines choses sont toujours écrites en langage assembleur, ce qui tend à être encore plus rapide. De plus en plus de choses sont écrites dans quelque chose d'autre, qui est lui-même écrit en C.

Chaque instruction que vous écrivez dans d'autres langages (et non Assembly) est généralement implémentée sous la forme de plusieurs instructions en C, qui sont compilées en code machine natif. Étant donné que ces autres langages ont tendance à exister afin d'obtenir un niveau d'abstraction plus élevé que C, ces instructions supplémentaires requises en C ont tendance à se concentrer sur l'ajout de sécurité, l'ajout de complexité et la gestion des erreurs. Ce sont souvent de bonnes choses, mais elles ont un coût , et ses noms sont vitesse et taille .

Personnellement, j'ai écrit dans des dizaines de langues couvrant la plupart du spectre disponible, et j'ai personnellement recherché la magie à laquelle vous faites allusion:

Comment puis-je avoir mon gâteau et le manger aussi? Comment puis-je jouer avec des abstractions de haut niveau dans ma langue préférée, puis descendre dans les moindres détails de C pour la vitesse?

Après quelques années de recherche, ma réponse est Python (sur C). Vous voudrez peut-être y jeter un œil. Soit dit en passant, vous pouvez également accéder à Assembly depuis Python (avec une aide mineure d'une bibliothèque spéciale).

D'un autre côté, un mauvais code peut être écrit dans n'importe quelle langue . Par conséquent, le code C (ou Assembly) n'est pas automatiquement plus rapide. De même, certaines astuces d'optimisation peuvent rapprocher des portions de code de langage de niveau supérieur du niveau de performance du C. brut, mais pour la plupart des applications, votre programme passe la plupart de son temps à attendre des personnes ou du matériel, de sorte que la différence n'a pas vraiment d'importance.

Prendre plaisir.


10
Cela ne s'applique pas vraiment aux langages compilés par JIT. Ce n'est pas comme si mon C # était en cours de compilation en IL qui est traduit en C qui est compilé en code machine. Non, l'IL est compilé en JIT - et le langage d'implémentation du JIT n'est pas pertinent à ce stade. Il s'agit simplement de produire du code machine.
Jon Skeet

3
Dieu ne plaise pas que je remette en question le légendaire Jon Skeet, mais il semble tout à fait pertinent que le code machine produit soit pour C # au lieu de C, donc il est "de niveau supérieur", a plus de fonctionnalités, a des contrôles de sécurité, etc. et être, par conséquent, plus lent que l '"équivalent" C.
Rob Williams

3
@ Jon: J'étais sur le point de dire quelque chose de similaire, mais le point est en fait quelque peu valable car de nombreux composants de base de la bibliothèque .NET sont réellement écrits en C et ont donc des limitations de vitesse de C. Il sera intéressant de voir comment cela va changer à l'avenir.
Konrad Rudolph

1
Cela semble être le contraire, d'autres compilateurs / interprètes / vms de langage sont fréquemment mais pas toujours écrits en c (ou du moins pour la couche la plus basse) car c est assez rapide (et dans de nombreux cas, le plus rapide).
Roman A. Taycher

2
Cette réponse n'est pas vraie. Comme indiqué ci-dessus, cela ne s'applique pas non plus aux langages JIT, mais également aux langages avec leurs propres compilateurs (qui, si des efforts extraordinaires y étaient déployés, pourraient générer du code plus rapide que les compilateurs C modernes). La seule autre classe de langues restante est les langues interprétées, et celles-ci ne sont pas plus lentes que C uniquement parce qu'elles sont écrites en C elles-mêmes, mais parce que les frais généraux d'interprétation, peu importe comment vous les découpez et même si l'interprète a été écrit en assembleur , est énorme.
Score_Under

38

Il y a beaucoup de questions là-dedans - surtout celles auxquelles je ne suis pas qualifié pour répondre. Mais pour ce dernier:

Qu'est-ce qui empêche les autres langages de compiler en binaire qui s'exécute tout aussi vite que C?

En un mot, l'abstraction.

C n'est qu'un ou deux niveaux d'abstraction loin du langage machine. Java et les langages .Net sont à au moins 3 niveaux d'abstraction loin de l'assembleur. Je ne suis pas sûr de Python et Ruby.

En règle générale, plus il y a de jouets de programmation (types de données complexes, etc.), plus vous vous éloignez du langage machine et plus vous devez faire de traduction.

Je suis ici et là, mais c'est l'essentiel.

Mise à jour ------- Il y a de bons commentaires sur ce post avec plus de détails.


3
Techniquement, Java et .Net sont infiniment abstraits du langage machine de la machine sur laquelle ils s'exécutent. Ils s'exécutent dans des machines virtuelles. Même avec JIT, le code d'origine doit être massivement massé pour obtenir quelque chose qui ressemble au code machine natif.
jmucchiello

1
Le code .net ne s'exécute pas sur une machine virtuelle. Il s'exécute en tant qu'instructions natives sur la plate-forme de processeur sur laquelle il s'exécute (32 bits x86, 64 bits x86 ou IA64).
Robert C.Barth

11
@ Robert: .net - t utiliser une machine virtuelle. Le code .net est compilé en bytecode qui est exécuté par la VM. La machine virtuelle convertit le bytecode en instructions natives au moment de l'exécution.
Robert Gamble

3
Il est très important de noter que Java et d'autres abstractions du langage OO ont affecté les jeux d'instructions du processeur. Les processeurs plus récents ont des instructions qui accélèrent l'exécution de Java si la machine virtuelle Java connaît ces optimisations et les utilise. Ce n'est pas énorme, mais c'est utile.
Adam Davis


35

Ce n'est pas tant que C est rapide que le modèle de coût de C est transparent . Si un programme C est lent, il est lent d'une manière évidente: en exécutant beaucoup d'instructions. Par rapport au coût des opérations en C, les opérations de haut niveau sur les objets (notamment la réflexion) ou les chaînes peuvent avoir des coûts qui ne sont pas évidents.

Deux langages qui se compilent généralement en binaires aussi rapides que C sont le ML standard (à l'aide du compilateur MLton ) et l' Objective Caml . Si vous consultez le jeu de benchmarks, vous constaterez que pour certains benchmarks, comme les arbres binaires, la version OCaml est plus rapide que C. (Je n'ai trouvé aucune entrée MLton.) Mais ne prenez pas la fusillade trop au sérieux; c'est, comme il est dit, un jeu, les résultats reflètent souvent l'effort que les gens ont mis pour régler le code.


Il est possible d'écrire du code non évidemment cher dans n'importe quelle langue. C'est juste que dans certaines langues, vous devez d'abord écrire une variante interne de Lisp ou Forth…
Donal Fellows

Rust correspond également à C dans les repères.
Stark

18

C n'est pas toujours plus rapide.

C est plus lent que, par exemple Modern Fortran.

C est souvent plus lent que Java pour certaines choses. (Surtout après que le compilateur JIT a essayé votre code)

C laisse l'alias du pointeur se produire, ce qui signifie que de bonnes optimisations ne sont pas possibles. En particulier, lorsque vous avez plusieurs unités d'exécution, cela entraîne des blocages de récupération de données. Ow.

L'hypothèse que l'arithmétique du pointeur fonctionne vraiment ralentit les performances gonflées sur certaines familles de processeurs (PIC en particulier!). Il utilisé pour aspirer le gros sur x86 segmenté.

Fondamentalement, lorsque vous obtenez une unité vectorielle ou un compilateur de parallélisation, C pue et le Fortran moderne s'exécute plus rapidement.

Les astuces du programmeur C comme le thunking (modification de l'exécutable à la volée) provoquent des blocages de prélecture du processeur.

Vous obtenez la dérive?

Et notre bon ami, le x86, exécute un jeu d'instructions qui, de nos jours, n'a que peu de rapport avec l'architecture réelle du CPU. Registres fantômes, optimiseurs de magasin de charge, tous dans le CPU. C est donc proche du métal virtuel. Le vrai métal, Intel ne vous laisse pas voir. (Historiquement, les processeurs VLIW étaient un peu difficiles, peut-être que ce n'est pas si mal.)

Si vous programmez en C sur un DSP haute performance (peut-être un TI DSP?), Le compilateur doit faire des choses délicates pour dérouler le C sur les multiples unités d'exécution parallèles. Donc, dans ce cas, C n'est pas proche du métal, mais il est proche du compilateur, qui fera toute l'optimisation du programme. Bizarre.

Et enfin, certains CPU (www.ajile.com) exécutent des bytecodes Java dans le matériel. C serait un PITA à utiliser sur ce CPU.


1
À quand remonte la dernière fois que thunking a été écrit, en C? Le x86 moderne est une interface avec une conception principalement RISC, mais cela n'a pas grand-chose à voir avec VLIW ...
Calyth

7
Une grande partie de votre message ignore l'existence de C99. En outre, de nombreux compilateurs C / C ++ proposent le mot clé restrict C99 (garantit l'absence d'alias de pointeur) comme extension.
Evan Teran

Je suppose que tout le monde suit / fait la transition pour suivre le top 25 CWE / SANS et évite de faire de nouveaux designs en C. Donc pas de champs verts C, si peu ou pas de C99.
Tim Williscroft

2
Pourriez-vous montrer un exemple lorsque c est plus lent que Fortenberry moderne?
Adam

Je ne suis pas sûr qu'il y ait jamais eu un moment où les compilateurs C rivalisaient très bien avec les meilleurs compilateurs Fortran. Bien sûr, il y a beaucoup de code que vous ne voudriez pas écrire dans FORTRAN 77 (sans parler de 66), mais les normes Fortran plus récentes ont été de plus en plus agréables.
tfb

11

Qu'est-ce qui empêche les autres langages de compiler en binaire qui s'exécute tout aussi vite que C?

Rien. Les langages modernes comme Java ou .NET sont plus axés sur la productivité du programmeur que sur les performances. Le matériel est bon marché de nos jours. La compilation en représentation intermédiaire offre également de nombreux avantages tels que la sécurité, la portabilité, etc.


je dirais la portabilité ici. Si vous voulez du code vraiment portable, écrivez-le en C et non dans un autre langage. Nous avons un code fonctionnant sur environ 25 systèmes d'exploitation. En partant de dos et threadX et en terminant sur Linux / XP, montrez-moi une autre langue qui peut le faire :)
Ilya

1
@Ilya, je ne suis pas d'accord. Il est tout aussi facile d'écrire du code non portable en C. Regardez à quel point il était pénible pour certains de porter en 64 bits. Les langages de bytecode pourraient fonctionner sur toutes les plateformes si vous avez le bon interprète de bytecode.
Calyth

1
@IIya, le code C portable est une exception plutôt qu'une règle, j'ai porté du code C entre différentes plates-formes matérielles / logicielles et je sais que c'est un cauchemar.
aku

Même pour PC Word, ce n'est pas le cas. Regardez dans la réalité la plupart des applications multiplateformes écrites en c / c ++, un peu en java. Pour le développement intégré de bas niveau, il n'y a tout simplement pas d'autre cas. C est de fait le langage le plus portable.
Ilya

@aku -> PORTING un mauvais code pourrait être un désastre, je suis d'accord. L'écriture de code portable dans ADVANCE - C est un meilleur choix. Je dirais que C ++ est une option, mais en allant sur une plate-forme embarquée, vous trouverez toujours un compilateur C décent, pour c ++, vous pourriez vous retrouver sans compilateur.
Ilya

8

Les principaux facteurs sont qu'il s'agit d'un langage de type statique et qui est compilé en code machine. De plus, comme c'est un langage de bas niveau, il ne fait généralement rien que vous ne lui dites pas.

Ce sont d'autres facteurs qui me viennent à l'esprit.

  • Les variables ne sont pas automatiquement initialisées
  • Aucune vérification des limites sur les tableaux
  • Manipulation non contrôlée du pointeur
  • Aucune vérification de dépassement d'entier
  • Variables de type statique
  • Les appels de fonction sont statiques (sauf si vous utilisez des pointeurs de fonction)
  • Les rédacteurs du compilateur ont eu beaucoup de temps pour améliorer le code d'optimisation. De plus, les gens programment en C dans le but d'obtenir les meilleures performances, donc il y a une pression pour optimiser le code.
  • Certaines parties de la spécification du langage sont définies par l'implémentation, les compilateurs sont donc libres de faire les choses de la manière la plus optimale

Cependant, la plupart des langages de type statique peuvent être compilés aussi rapidement ou plus rapidement que C, surtout s'ils peuvent faire des suppositions que C ne peut pas en raison de l'alias de pointeur, etc.


C bas niveau? Je suppose que c'est une signification relative maintenant, par rapport à Java oui mais par rapport à l'assemblage non. Bon post, m'a fait réfléchir.
Mark

Tu as raison, c'est définitivement relatif. Ce que je veux dire, c'est qu'il est "proche de la machine" et ne vous aide pas à faire des choses comme la gestion de la mémoire ou le suivi de la taille des baies.
Matthew Crumley

2
C est un langage de bas niveau. C a toujours été un langage de bas niveau. Vous traduisez manuellement le code C dans l'assembleur sans trop de difficulté.
Robert C.Barth

2
@Robert: C était autrefois considéré comme un langage de haut niveau car comparé à l'assemblage (qui était très courant), il l'était. Il est considéré comme une langue de bas niveau par rapport à la majorité des langues utilisées aujourd'hui.
Robert Gamble

Honnêtement, c'est une réponse très biaisée. Merde près de tous les programmeurs C font la vérification des limites, etc. Pourtant, C est encore beaucoup plus rapide que C ++.
MarcusJ

8

Je suppose que vous avez oublié que le langage d'assemblage est aussi un langage :)

Mais sérieusement, les programmes C ne sont plus rapides que lorsque le programmeur sait ce qu'il fait. Vous pouvez facilement écrire un programme C qui s'exécute plus lentement que les programmes écrits dans d'autres langues qui font le même travail.

La raison pour laquelle C est plus rapide est qu'il est conçu de cette façon. Il vous permet de faire beaucoup de choses de "niveau inférieur" qui aident le compilateur à optimiser le code. Ou, dirons-nous, vous le programmeur êtes responsable de l'optimisation du code. Mais c'est souvent assez délicat et sujet aux erreurs.

D'autres langues, comme d'autres déjà mentionnées, se concentrent davantage sur la productivité du programmeur. Il est communément admis que le temps programmeur est beaucoup plus cher que le temps machine (même dans l'ancien temps). Il est donc très logique de minimiser le temps que les programmeurs passent à écrire et déboguer des programmes au lieu de la durée d'exécution des programmes. Pour ce faire, vous sacrifierez un peu ce que vous pouvez faire pour accélérer le programme car beaucoup de choses sont automatisées.


3
Bien que si vous avez écrit un programme une fois en C puis à nouveau dans Assembly, la version C serait probablement plus rapide car le compilateur est plus intelligent que vous.
mk12

7

Pour la plupart, chaque instruction C correspond à très peu d'instructions d'assembleur. Vous écrivez essentiellement du code machine de niveau supérieur, vous avez donc le contrôle de presque tout ce que fait le processeur. De nombreux autres langages compilés, tels que C ++, ont beaucoup d'instructions simples qui peuvent se transformer en beaucoup plus de code que vous ne le pensez (fonctions virtuelles, constructeurs de copie, etc.) Et les langages interprétés comme Java ou Ruby ont une autre couche de instructions que vous ne voyez jamais - la machine virtuelle ou l'interpréteur.


Et certaines de ces langues de haut niveau se targuent d’être capables de supprimer la plupart des dépouilles qu’elles ont ajoutées en premier lieu. Des choses comme copier l'élision, optimiser la valeur de retour, déplacer la construction / affectation, etc. en C ++.
cmaster - réintègre monica le

Tout se résume donc au nombre d'instructions d'assemblage générées à partir du code. Il y a plus d'instructions d'assemblage par ligne de code de haut niveau, plus les performances en souffrent?
ENDEESA

Cela peut être une simplification excessive, mais il existe une relation directe entre le nombre d'instructions d'assemblage et la vitesse du programme. Il y a un minimum de temps pour que le processeur exécute chaque instruction. À mon humble avis, un langage qui vous permet de comprendre facilement combien d'instructions vous écrivez vous aide à écrire du code plus efficace. (Il y a d'autres coûts de temps du processeur, comme les erreurs de branchement et de cache, mais même là, moins d'abstraction permet de clarifier ce que fait le CPU).
AShelly


7

C ++ est plus rapide en moyenne (comme c'était initialement, en grande partie un surensemble de C, bien qu'il y ait quelques différences). Cependant, pour des benchmarks spécifiques, il existe souvent un autre langage qui est plus rapide.

https://benchmarksgame-team.pages.debian.net/benchmarksgame/

fannjuch-redux a été le plus rapide à Scala

n-bodyet fastaétaient plus rapides à Ada.

spectral-norm était le plus rapide à Fortran.

reverse-complement, mandelbrotEt pidigitsont été le plus rapide ATS.

regex-dna était le plus rapide en JavaScript.

chameneou-redux était le plus rapide est Java 7.

thread-ring a été le plus rapide à Haskell.

Les autres benchmarks étaient les plus rapides en C ou C ++.


"car c'est un super ensemble de C" - Non, C ++ n'est pas un surensemble de C.
PP

1
extern "C"n'a rien à voir avec C ++ étant un sur - ensemble de C.
PP

2
C'est comme dire que ça system("bash script.sh");marche pour n'importe quel script bash, et donc C est un sur-ensemble de bash. extern "C"fournit la liaison C en C ++ en raison du changement de nom. Alors que l'appel de X en tant que sur-ensemble de Y signifie que tout ce qui peut être fait en Y peut également l'être en X, ce qui n'est pas le cas de C ++. Il existe plusieurs constructions de langage valides en C mais pas en C ++.
PP

1
@PP Il n'y a rien dans la norme C ++ qui rend obligatoire bashun programme de ligne de commande disponible. S'il le faisait et incluait la version / spécification de bash qui devait être prise en charge, je considérerais que c'est un surensemble.
Peter Lawrey

1
il est trivialement facile d'écrire du code C qui n'est pas du code C ++, par exemplestruct foo { int: this; }; typedef float foo;
Jasen

6

Beaucoup de ces réponses donnent des raisons valables pour lesquelles C est, ou n'est pas, plus rapide (en général ou dans des scénarios spécifiques). Il est indéniable que:

  • De nombreuses autres langues proposent des fonctionnalités automatiques que nous tenons pour acquises. La vérification des limites, la vérification du type au moment de l'exécution et la gestion automatique de la mémoire, par exemple, ne sont pas gratuites. Il y a au moins un certain coût associé à ces fonctionnalités, auquel nous ne pouvons pas penser - ou même réaliser - lors de l'écriture de code qui utilise ces fonctionnalités.
  • Le pas de la source à la machine n'est souvent pas aussi direct dans les autres langues qu'en C.
  • OTOH, dire que le code C compilé s'exécute plus rapidement que les autres codes écrits dans d'autres langages est une généralisation qui n'est pas toujours vraie. Les contre-exemples sont faciles à trouver (ou à inventer).

Malgré tout cela, il y a autre chose que j'ai remarqué qui, je pense, affecte la performance comparative de C par rapport à de nombreux autres langages plus que tout autre facteur. En être témoin:

D'autres langages facilitent souvent l'écriture de code qui s'exécute plus lentement. Souvent, il est même encouragé par les philosophies de conception de la langue. Corollaire: un programmeur C est plus susceptible d'écrire du code qui n'effectue pas d'opérations inutiles.

Par exemple, considérons un simple programme Windows dans lequel une seule fenêtre principale est créée. La version AC remplirait une WNDCLASS[EX]structure qui serait passée à RegisterClass[Ex], puis appeler CreateWindow[Ex]et entrer une boucle de message. Le code très simplifié et abrégé suit:

WNDCLASS wc;
MSG      msg;

wc.style         = 0;
wc.lpfnWndProc   = &WndProc;
wc.cbClsExtra    = 0;
wc.cbWndExtra    = 0;
wc.hInstance     = hInstance;
wc.hIcon         = NULL;
wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName  = NULL;
wc.lpszClassName = "MainWndCls";

RegisterClass(&wc);

CreateWindow("MainWndCls", "", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
             CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

while(GetMessage(&msg, NULL, 0, 0)){
    TranslateMessage(&msg);
    DispatchMessage(&msg);
}

Un programme équivalent en C # pourrait être une seule ligne de code:

Application.Run(new Form());

Cette ligne de code fournit toutes les fonctionnalités de près de 20 lignes de code C et ajoute certaines choses que nous avons omises, telles que la vérification des erreurs. La bibliothèque plus riche et plus complète (par rapport à celles utilisées dans un projet C typique) a fait beaucoup de travail pour nous, nous laissant ainsi le temps d'écrire de nombreux extraits de code qui nous paraissent courts mais qui impliquent de nombreuses étapes en arrière-plan.

Mais une bibliothèque riche permettant un ballonnement de code facile et rapide n'est pas vraiment mon point. Mon point est plus apparent lorsque vous commencez à examiner ce qui se passe réellement lorsque notre petit one-liner s'exécute. Pour le plaisir, parfois, activez l'accès aux sources .NET dans Visual Studio 2008 ou supérieur, et entrez dans le simple one-linef ci-dessus. L'un des petits joyaux amusants que vous rencontrerez est ce commentaire dans le getter pour Control.CreateParams:

// In a typical control this is accessed ten times to create and show a control.
// It is a net memory savings, then, to maintain a copy on control.
// 
if (createParams == null) {
    createParams = new CreateParams(); 
} 

Dix fois . Les informations à peu près équivalentes à la somme de ce qui est stocké dans une WNDCLASSEXstructure et de ce qui est transmis CreateWindowExsont extraites de la Controlclasse dix fois avant d' être stockées dans une WNDCLASSEXstructure et transmises à RegisterClassExet CreateWindowEx.

Dans l'ensemble, le nombre d'instructions exécutées pour effectuer cette tâche très basique est de 2 à 3 ordres de grandeur de plus en C # qu'en C. Une partie de cela est due à l'utilisation d'une bibliothèque riche en fonctionnalités, qui est nécessairement généralisée, par rapport à notre simple code C qui fait exactement ce dont nous avons besoin et rien de plus. Mais cela est dû en partie au fait que la nature modulaire et orientée objet du framework .NET se prête à de nombreuses répétitions d'exécution qui sont souvent évitées par une approche procédurale.

Je n'essaye pas de choisir C # ou le framework .NET. Je ne dis pas non plus que la modularisation, la généralisation, les fonctionnalités de bibliothèque / langage, la POO, etc. sont de mauvaises choses . J'ai utilisé pour faire la plupart de mon développement en C, plus tard en C ++, et plus récemment en C #. De même, avant C, j'utilisais principalement l'assemblage. Et à chaque étape «plus haut» de ma langue, j'écris des programmes meilleurs, plus faciles à maintenir et plus robustes en moins de temps. Ils ont cependant tendance à s'exécuter un peu plus lentement.


2
C'est un problème d'API, pas un problème de langue.
Arafangion

1
@Arafangion: Je comprends ce que vous dites, mais cela manque un peu le sujet. La bibliothèque riche en fonctionnalités est activée (et, en quelque sorte, demandée) par le langage riche en fonctionnalités. Et ce n'est pas seulement la bibliothèque. La bibliothèque n'est qu'un exemple d'utilisation courante de la langue. Le code d'application typique dans n'importe quelle langue ressemble généralement aux bibliothèques généralement utilisées dans cette langue. C'est vraiment plus un état d'esprit favorisé par la langue. Par exemple, les langages OO passent généralement plus de temps à allouer, construire, détruire et désallouer des objets que les langages avec moins de prise en charge OOP.
P papa

Je concède qu'un choix donné de langue implique généralement une plate-forme et une bibliothèque particulières, c'est pourquoi j'ai fait ce commentaire (pour que le lecteur en soit plus conscient), mais cela dit, utiliser (par exemple) C ++ sur Windows est un bête très différente, disons, C ++ sur linux et différente à nouveau avec C ++ sur Android. Un autre exemple est Python - nous avons CPython, Jython, PyPy et IronPython - qui utilisent tous des bibliothèques très différentes.
Arafangion

Mais en utilisant l'un de ces Pythons, les développeurs auront tendance à écrire des applications d'une certaine manière. Par exemple, ils peuvent lire et écrire à partir d'un fichier texte, créant de nouveaux objets avec les données qu'ils lisent. En C, en revanche, un développeur ferait plus probablement une allocation unique d'un tableau de structures, et lire et écrire ces structures à partir d'un fichier binaire. C'est, bien sûr, simplement un exemple artificiel qui tente d'illustrer le point que j'essaie de faire sur l' état d' esprit .
P Daddy

6

Je ne pense pas que quiconque ait mentionné le fait que beaucoup plus d'efforts ont été consacrés aux compilateurs C que tout autre compilateur, à l'exception peut-être de Java.

C est extrêmement optimisable pour de nombreuses raisons déjà mentionnées - plus que presque tout autre langage. Donc, si la même quantité d'efforts est mise dans d'autres compilateurs de langage, C sera probablement toujours en tête.

Je pense qu'il y a au moins un langage candidat qui, avec effort, pourrait être optimisé mieux que C et donc nous pourrions voir des implémentations qui produisent des binaires plus rapides. Je pense au mars numérique D parce que le créateur a pris soin de construire un langage qui pourrait potentiellement être mieux optimisé que C. Il peut y avoir d'autres langages qui ont cette possibilité. Cependant, je ne peux pas imaginer que n'importe quel langage aura des compilateurs plus de quelques pour cent plus rapides que les meilleurs compilateurs C. J'adorerais me tromper.

Je pense que le vrai "fruit à faible pendaison" sera dans des langages conçus pour être FACILES à optimiser pour les humains. Un programmeur compétent peut accélérer n'importe quel langage - mais parfois vous devez faire des choses ridicules ou utiliser des constructions non naturelles pour y arriver. Bien que cela prenne toujours des efforts, un bon langage devrait produire un code relativement rapide sans avoir à se soucier exactement de la façon dont le programme est écrit.

Il est également important (au moins pour moi) que le pire des cas ait tendance à être rapide. Il existe de nombreuses "preuves" sur le Web que Java est aussi rapide ou plus rapide que C, mais cela est basé sur des exemples de sélection de cerises. Je ne suis pas un grand fan de C, mais je sais que TOUT ce que j'écris en C va bien fonctionner. Avec Java, il fonctionnera «probablement» à moins de 15% de la vitesse, généralement à moins de 25%, mais dans certains cas, il peut être bien pire. Tous les cas où il est tout aussi rapide ou dans quelques pour cent sont généralement dus au fait que la plupart du temps est passé dans le code de bibliothèque qui est fortement optimisé C de toute façon.


5

C'est en fait un peu un mensonge perpétué. S'il est vrai que les programmes C sont souvent plus rapides, ce n'est pas toujours le cas, surtout si le programmeur C n'est pas très bon dans ce domaine.

Un gros trou flagrant que les gens ont tendance à oublier, c'est quand le programme doit bloquer pour une sorte d'E / S, comme l'entrée utilisateur dans n'importe quel programme GUI. Dans ces cas, peu importe la langue que vous utilisez, car vous êtes limité par la vitesse à laquelle les données peuvent arriver plutôt que par la vitesse à laquelle vous pouvez les traiter. Dans ce cas, peu importe si vous utilisez C, Java, C # ou même Perl; vous ne pouvez pas aller plus vite que les données ne peuvent entrer.

L'autre chose importante est que l'utilisation de la récupération de place et l'utilisation de pointeurs appropriés permettent à la machine virtuelle d'effectuer un certain nombre d'optimisations non disponibles dans d'autres langues. Par exemple, la JVM est capable de déplacer des objets sur le tas pour le défragmenter. Cela rend les allocations futures beaucoup plus rapides car le prochain indice peut simplement être utilisé plutôt que de le rechercher dans une table. Les machines virtuelles Java modernes n'ont pas non plus à réellement désallouer la mémoire; au lieu de cela, ils déplacent simplement les objets vivants lors de leur GC et la mémoire dépensée des objets morts est récupérée essentiellement gratuitement.

Cela soulève également un point intéressant à propos de C et encore plus en C ++. Il y a quelque chose d'une philosophie de conception de «Si vous n'en avez pas besoin, vous ne payez pas pour cela. Le problème est que si vous le voulez, vous finissez par payer par le nez. Par exemple, l'implémentation de vtable en Java a tendance à être bien meilleure que les implémentations C ++, donc les appels de fonctions virtuelles sont beaucoup plus rapides. D'un autre côté, vous n'avez pas d'autre choix que d'utiliser des fonctions virtuelles en Java et elles coûtent toujours quelque chose, mais dans les programmes qui utilisent beaucoup de fonctions virtuelles, le coût réduit s'additionne.


1
"L'implémentation de vtable en Java a tendance à être bien meilleure que les implémentations C ++, donc les appels de fonctions virtuelles sont beaucoup plus rapides.". Comment diable pouvez-vous aller plus vite que MOV EAX, [ECX]; CALL [EAX + someindex]; ? À moins que vous ne puissiez appeler une fonction sans la rechercher, cela semble assez optimal.
Frans-Willem

@Frans - un compilateur JIT (tel que Java HotSpot) peut incorporer la recherche vtable s'il détermine qu'un objet donné est toujours d'un type donné. C ++ le fera également s'il connaît les mêmes informations au moment de la compilation, mais il est plus facile de faire cette optimisation avec le bytecode Java qu'avec les instructions machine x86.
Tom

6
@James - Argumenter que «les E / S rendent les performances moins importantes» n'invalide pas l'énoncé «C est plus rapide que les autres langages». Ce n'est pas un trou flagrant, c'est un argument paille.
Tom

Il aurait été préférable d'avoir utilisé la gestion des chaînes de C (et aussi la bibliothèque C standard) comme exemple, car c'est un domaine où C est pauvre. La plupart des autres langues font mieux, même avec un code de départ simpliste.
Donal Fellows

@DonalFellows les fonctions mem * peuvent être plus rapides que les fonctions str * sur certaines tâches, mais la gestion des chaînes est efficace si on y prend garde. avez-vous une référence spécifique en tête?
Jasen

4

Ce n'est pas tant la langue que les outils et les bibliothèques. Les bibliothèques et compilateurs disponibles pour C sont beaucoup plus anciens que pour les langages plus récents. Vous pourriez penser que cela les ralentirait, mais au contraire.

Ces bibliothèques ont été écrites à une époque où la puissance de traitement et la mémoire étaient précieuses. Ils devaient être rédigés de manière très efficace pour pouvoir fonctionner. Les développeurs de compilateurs C ont également eu longtemps à travailler dans toutes sortes d'optimisations intelligentes pour différents processeurs. La maturité et l'adoption généralisée de C lui confèrent un avantage significatif sur d'autres langues du même âge. Cela donne également à C un avantage de vitesse par rapport aux outils plus récents qui ne mettent pas autant l'accent sur les performances brutes que C le devait.


4

Le manque d'abstraction est ce qui rend C plus rapide. Si vous écrivez une instruction de sortie, vous savez exactement ce qui se passe. Si vous écrivez une instruction de sortie en java, elle est compilée dans un fichier de classe qui est ensuite exécuté sur une machine virtuelle introduisant une couche d'abstraction. Le manque de fonctionnalités orientées objet en tant que partie du langage augmente également sa vitesse pour réduire le code généré. Si vous utilisez C comme langage orienté objet, vous effectuez tout le codage pour des choses telles que les classes, l'inharitence, etc. Cela signifie plutôt que faites quelque chose de suffisamment généralisé pour tout le monde avec la quantité de code et la pénurie de performances qui ne nécessitent que vous écrivez ce dont vous avez besoin pour faire le travail.


4

Étonnant de voir que le vieux mythe "C / C ++ doit être plus rapide que Java car Java est interprété" est toujours vivant. Il y a des articles qui remontent à quelques années , ainsi que des articles plus récents , qui expliquent avec des concepts ou des mesures pourquoi ce n'est tout simplement pas toujours le cas .

Les implémentations de machines virtuelles actuelles (et pas seulement la JVM, soit dit en passant) peuvent tirer parti des informations recueillies lors de l'exécution du programme pour régler dynamiquement le code pendant son exécution, en utilisant une variété de techniques:

  • rendre des méthodes fréquentes au code machine,
  • l'inclusion de petites méthodes,
  • réglage du verrouillage

et une variété d'autres ajustements basés sur la connaissance de ce que le code fait réellement et sur les caractéristiques réelles de l'environnement dans lequel il s'exécute.


Je suis d'accord que Java a fait des améliorations de performances significatives au cours des dernières années, ce qui le rapproche beaucoup du C en termes de performances brutes, mais il faudra un certain temps pour comprendre que cela a été si lent pendant si longtemps. Mais qui parlait de Java de toute façon?
Robert Gamble

Java est un "autre langage" référencé par l'OP, n'est-ce pas?
Robert C.Barth

@Robert: "autres langues", pluriel, aucune mention d'une langue spécifique autre que C. Comment lisez-vous "Java" à partir de cela?
Robert Gamble

@Roberd: Plusieurs des réponses qui avaient été postées avant que je ne rencontre la question parlaient de Java (ou d'autres langages dont l'implémentation se fait souvent via interprète ou VM).
joel.neely

3
@Joel - Si vous connaissez votre matériel cible, la plupart des optimisations que la JVM peut effectuer au moment de l'exécution peuvent également être effectuées en utilisant l'optimisation guidée par le profil avec C ou C ++. Cela fait une énorme différence et repousse généralement C et C ++ en tête, car ils n'ont pas à "apprendre" lors de l'exécution.
Tom

4

Le code le plus rapide serait le code machine soigneusement fabriqué à la main. L'assembleur sera presque aussi bon. Les deux sont de très bas niveau et il faut beaucoup d'écriture de code pour faire les choses. C est un peu au-dessus de l'assembleur. Vous avez toujours la possibilité de contrôler les choses à un niveau très bas dans la machine réelle, mais il y a suffisamment d'abstraction pour l'écrire plus rapidement et plus facilement que l'assembleur. D'autres langages tels que C # et JAVA sont encore plus abstraits. Alors que l'assembleur et le code machine sont appelés langages de bas niveau, C # et JAVA (et bien d'autres) sont appelés langages de haut niveau. C est parfois appelé langage de niveau intermédiaire.


En lisant votre réponse, deux mots dans tout le paragraphe attiraient mes yeux vers eux, comme un aimant tirant des métaux. Le mot est JAVA, deux fois dans le paragraphe. Jamais vu auparavant écrit en toutes lettres, et ça a l'air bien :-)
Sнаđошƒаӽ

3

Ne prenez pas le mot pour quelqu'un, regardez le désassemblage pour C et votre langue de choix dans n'importe quelle partie critique de la performance de votre code. Je pense que vous pouvez simplement regarder dans la fenêtre de démontage lors de l'exécution dans Visual Studio pour voir .Net démonté. Cela devrait être possible s'il est difficile pour Java d'utiliser windbg, mais si vous le faites avec .Net, de nombreux problèmes seront les mêmes.

Je n'aime pas écrire en C si je n'en ai pas besoin, mais je pense que la plupart des affirmations formulées dans ces réponses qui vantent la vitesse des langages autres que C peuvent être mises de côté en démontant simplement la même routine en C et dans la langue de votre choix de niveau supérieur, en particulier si de nombreuses données sont impliquées, comme cela est courant dans les applications critiques pour les performances. Fortran peut être une exception dans son domaine d'expertise, je ne sais pas. Est-ce un niveau supérieur à C?

La première fois que j'ai comparé du code JITed avec du code natif, j'ai résolu toutes les questions de savoir si le code .Net pouvait fonctionner de manière comparable au code C. Le niveau supplémentaire d'abstraction et tous les contrôles de sécurité ont un coût important. Les mêmes coûts s'appliqueraient probablement à Java, mais ne me croyez pas sur parole, essayez-le sur quelque chose où les performances sont critiques. (Quelqu'un en sait-il assez sur JITed Java pour localiser une procédure compilée en mémoire? Cela devrait certainement être possible)


2

1) Comme d'autres l'ont dit, C fait moins pour vous. Pas de variables d'initialisation, pas de vérification des limites du tableau, pas de gestion de la mémoire, etc. Ces fonctionnalités dans d'autres langages coûtent en mémoire et en cycles CPU que C ne dépense pas.

2) Les réponses disant que C est moins abstrait et donc plus rapide ne sont qu'à moitié correctes je pense. Techniquement parlant, si vous aviez un "compilateur suffisamment avancé" pour le langage X, alors le langage X pourrait approcher ou égaler la vitesse de C. La différence avec C est que puisqu'il correspond si évidemment (si vous avez suivi un cours d'architecture) et directement au langage d'assemblage que même un compilateur naïf peut faire un travail décent. Pour quelque chose comme Python, vous avez besoin d'un compilateur très avancé pour prédire les types probables d'objets et générer du code machine à la volée - la sémantique de C est suffisamment simple pour qu'un simple compilateur puisse bien faire.


2

Au bon vieux temps, il n'y avait que deux types de langues: compilées et interprétées.

Les langages compilés ont utilisé un «compilateur» pour lire la syntaxe du langage et le convertir en code de langage d'assemblage identique, qui pourrait être directement sur le CPU. Les langages interprétés utilisaient deux schémas différents, mais essentiellement la syntaxe du langage a été convertie en une forme intermédiaire, puis exécutée dans un "interprète", un environnement pour exécuter le code.

Ainsi, dans un sens, il y avait une autre "couche" - l'interprète - entre le code et la machine. Et, comme toujours dans un ordinateur, plus signifie plus de ressources sont utilisées. Les interprètes étaient plus lents, car ils devaient effectuer plus d'opérations.

Plus récemment, nous avons vu plus de langages hybrides comme Java, qui utilisent à la fois un compilateur et un interprète pour les faire fonctionner. C'est compliqué, mais une JVM est plus rapide, plus sophistiquée et bien plus optimisée que les anciens interprètes, donc elle représente un bien meilleur changement de performance (au fil du temps) plus proche du code compilé juste. Bien sûr, les nouveaux compilateurs ont également des astuces d'optimisation plus sophistiquées, ils ont donc tendance à générer un code bien meilleur qu'auparavant. Mais la plupart des optimisations, le plus souvent (mais pas toujours), font un certain type de compromis de sorte qu'elles ne sont pas toujours plus rapides en toutes circonstances. Comme tout le reste, rien n'est gratuit, les optimiseurs doivent donc se vanter de quelque part (bien qu'il l'utilise souvent en utilisant le CPU au moment de la compilation pour économiser le CPU à l'exécution).

Pour en revenir au C, c'est un langage simple, qui peut être compilé en assemblage assez optimisé puis exécuté directement sur la machine cible. En C, si vous incrémentez un entier, il est plus que probable que ce n'est qu'une étape d'assembleur dans le CPU, en Java cependant, cela pourrait finir par être beaucoup plus que cela (et pourrait également inclure un peu de récupération de place: -) C vous propose une abstraction beaucoup plus proche de la machine (l'assembleur est le plus proche), mais vous finissez par devoir faire beaucoup plus de travail pour le faire fonctionner et ce n'est pas aussi protégé, facile à utiliser ou sans erreur. La plupart des autres langues vous offrent une abstraction plus élevée et prennent en charge plus de détails sous-jacents pour vous, mais en échange de leurs fonctionnalités avancées, elles nécessitent plus de ressources pour fonctionner. Au fur et à mesure que vous généralisez certaines solutions, vous devez gérer une gamme plus large d'informatique,

Paul.


"En C, si vous incrémentez un entier, il est plus que probable qu'il ne s'agit que d'une étape d'assembleur dans le CPU" Ce n'est pas tout à fait vrai. Si cet entier n'est pas dans le registre CPU, alors vous devez avoir le code machine pour le récupérer dans la mémoire, l'incrémenter, le réécrire dans la mémoire. À peu près la même chose devrait se produire lors de l'exécution du code Java. Et je ne comprends pas pourquoi "++ i" déclencherait par lui-même un cycle GC.
quant_dev

@quant_dev: "vous .. devez ... le récupérer dans la mémoire, l'incrémenter, le réécrire ...". Peut-être peut-être pas. Le x86, par exemple, a des instructions qui fonctionnent sur les données en mémoire. ++ipourrait compiler pour "ajouter [ebp-8], 1". Cela ne veut pas dire que la récupération, l'incrémentation, le stockage ne se produisent toujours pas, mais cela est pris en charge par le processeur et n'est qu'une instruction, comme l'a dit Paul.
P Daddy

... ce qui n'est toujours pas pertinent par rapport au POV de la performance, car il peut ne s'agir que d'une seule instruction, mais implique toujours d'attendre que les données arrivent au processeur. Cache manque et tout ça.
quant_dev

Non, je ne dirais pas que ce n'est pas pertinent. Une instruction CPU occupe généralement moins d'octets de code que plusieurs instructions CPU, ce qui donne de meilleures performances de cache sur le segment de code. Une instruction CPU prend également moins de place sur le pipeline du CPU, et les multiples étapes (extraction, incrémentation, stockage) peuvent être gérées, peut-être en parallèle, par les différentes étapes du pipeline. En fait, certaines parties d'une opération peuvent même être ignorées si elles peuvent être fusionnées avec d'autres opérations sur le pipeline. Par exemple, le stockage d'une valeur peut être fusionné avec un chargement ultérieur de la même valeur.
P Daddy

2

Mis à part les techniques d'optimisation avancées telles que l' optimisation des points chauds , les méta-algorithmes précompilés et diverses formes de parallélisme , la vitesse fondamentale d'un langage est fortement corrélée à la complexité implicite en arrière-plan nécessaire pour prendre en charge les opérations qui seraient généralement être spécifié dans les boucles internes .

Le plus évident est peut-être la vérification de la validité des références de mémoire indirectes, telles que la vérification des pointeurs nullet la vérification des index par rapport aux limites des tableaux. La plupart des langages de haut niveau effectuent ces vérifications implicitement, mais pas C. Cependant, ce n'est pas nécessairement une limitation fondamentale de ces autres langages - un compilateur suffisamment intelligent peut être capable de supprimer ces vérifications des boucles internes d'un algorithme à travers une certaine forme de mouvement de code invariant en boucle .

L'avantage le plus fondamental de C (et dans une mesure similaire le C ++ étroitement lié) est une forte dépendance à l' allocation de mémoire basée sur la pile , qui est intrinsèquement rapide pour l'allocation, la désallocation et l'accès. En C (et C ++), la pile d'appels principale peut être utilisée pour l'allocation de primitives, de tableaux et d'agrégats ( struct/ class).

Alors que C offre la possibilité d' allouer dynamiquement de la mémoire de taille et de durée de vie arbitraires (en utilisant le soi-disant «tas»), cela est évité par défaut (la pile est utilisée à la place).

De façon alléchante, il est parfois possible de répliquer la stratégie d'allocation de mémoire C dans les environnements d'exécution d'autres langages de programmation. Cela a été démontré par asm.js , qui permet au code écrit en C ou C ++ d'être traduit en un sous-ensemble de JavaScript et de s'exécuter en toute sécurité dans un environnement de navigateur Web - avec une vitesse quasi-native.


Comme un peu à part, un autre domaine où C et C ++ surpassent la plupart des autres langages pour la vitesse est la capacité à s'intégrer de manière transparente avec les jeux d'instructions machine natifs. Un exemple notable de ceci est la disponibilité (dépendante du compilateur et de la plate-forme) des intrinsèques SIMD qui prennent en charge la construction d'algorithmes personnalisés qui tirent parti du matériel de traitement parallèle désormais presque omniprésent - tout en utilisant les abstractions d'allocation de données fournies par le langage (inférieur -l'allocation des registres de niveau est gérée par le compilateur).


1
Certains de ces avantages d'allocation de mémoire de C peuvent également être répliqués dans d'autres langages par des compilateurs intelligents (voir ici ). J'ai l'impression, cependant, que c'est en quelque sorte structurellement très difficile à faire - en particulier pour les types de données non primitifs. Cet article mentionne l'idée d'un objet non échappant qui peut être alloué par pile en tant qu'optimisation en Java.
nobar

2

J'ai trouvé une réponse sur le lien expliquant pourquoi certains langages sont plus rapides et certains plus lents, j'espère que cela clarifiera davantage pourquoi C ou C ++ est plus rapide que d'autres, Il existe également d'autres langages plus rapides que C, mais nous ne pouvons pas utilisez-les tous. Quelques explications -

L'une des principales raisons pour lesquelles Fortran reste important est qu'il est rapide: les routines de calcul des nombres écrites en Fortran ont tendance à être plus rapides que les routines équivalentes écrites dans la plupart des autres langues. Les langages qui concurrencent Fortran dans cet espace - C et C ++ - sont utilisés parce qu'ils sont compétitifs avec cette performance.

Cela soulève la question: pourquoi? En quoi C ++ et Fortran les rendent-ils rapides, et pourquoi surpassent-ils les autres langages populaires, tels que Java ou Python?

Interpréter ou compiler Il existe de nombreuses façons de catégoriser et de définir les langages de programmation, selon le style de programmation qu'ils encouragent et les fonctionnalités qu'ils offrent. En ce qui concerne les performances, la plus grande distinction est entre les langages interprétés et les langages compilés.

La fracture n'est pas difficile; il y a plutôt un spectre. À une extrémité, nous avons des langages compilés traditionnels, un groupe qui comprend Fortran, C et C ++. Dans ces langages, il existe une étape de compilation discrète qui traduit le code source d'un programme sous une forme exécutable que le processeur peut utiliser.

Ce processus de compilation comporte plusieurs étapes. Le code source est analysé et analysé. Les erreurs de codage de base telles que les fautes de frappe et les fautes d'orthographe peuvent être détectées à ce stade. Le code analysé est utilisé pour générer une représentation en mémoire, qui peut également être utilisée pour détecter des erreurs - cette fois, des erreurs sémantiques, telles que des fonctions d'appel qui n'existent pas, ou essayer d'effectuer des opérations arithmétiques sur des chaînes de texte.

Cette représentation en mémoire est ensuite utilisée pour piloter un générateur de code, la partie qui produit du code exécutable. L'optimisation de code, pour améliorer les performances du code généré, est effectuée à différents moments de ce processus: des optimisations de haut niveau peuvent être effectuées sur la représentation du code, et des optimisations de niveau inférieur sont utilisées sur la sortie du générateur de code.

L'exécution effective du code se produit plus tard. L'ensemble du processus de compilation est simplement utilisé pour créer quelque chose qui peut être exécuté.

À l'opposé, nous avons des interprètes. Les interprètes incluront une étape d'analyse similaire à celle du compilateur, mais celle-ci est ensuite utilisée pour piloter l'exécution directe, le programme étant exécuté immédiatement.

L'interprète le plus simple a en son sein du code exécutable correspondant aux différentes fonctionnalités prises en charge par le langage - il aura donc des fonctions pour ajouter des nombres, joindre des chaînes, quoi que ce soit d'autre dans un langage donné. En analysant le code, il recherchera la fonction correspondante et l'exécutera. Les variables créées dans le programme seront conservées dans une sorte de table de recherche qui mappe leurs noms à leurs données.

L'exemple le plus extrême du style interprète est quelque chose comme un fichier batch ou un script shell. Dans ces langages, le code exécutable n'est souvent même pas intégré à l'interpréteur lui-même, mais plutôt à des programmes autonomes séparés.

Alors pourquoi cela fait-il une différence dans les performances? En général, chaque couche d'indirection réduit les performances. Par exemple, le moyen le plus rapide pour ajouter deux nombres est d'avoir ces deux nombres dans les registres du processeur et d'utiliser l'instruction d'ajout du processeur. C'est ce que les programmes compilés peuvent faire; ils peuvent mettre des variables dans des registres et tirer parti des instructions du processeur. Mais dans les programmes interprétés, ce même ajout peut nécessiter deux recherches dans une table de variables pour récupérer les valeurs à ajouter, puis appeler une fonction pour effectuer l'ajout. Cette fonction peut très bien utiliser la même instruction de processeur que celle utilisée par le programme compilé pour effectuer l'addition réelle, mais tout le travail supplémentaire avant que l'instruction puisse réellement être utilisée ralentit les choses.

Si vous voulez en savoir plus, veuillez vérifier la source


1

Certains algorithmes C ++ sont plus rapides que C, et certaines implémentations d'algorithmes ou de modèles de conception dans d'autres langages peuvent être plus rapides que C.

Lorsque les gens disent que C est rapide et passent ensuite à parler d'un autre langage, ils utilisent généralement les performances de C comme référence.


2
"Certains algorithmes C ++ sont plus rapides que C" n'a pas de sens. Tout "algorithme C ++" peut être écrit en C et vice versa. Les algorithmes sont indépendants du langage. C ++ ajoute essentiellement des fonctionnalités à C - et aucune de ces nouvelles fonctionnalités ne conduit à des algorithmes plus rapides (bien qu'ils soient peut-être plus faciles à écrire).
Joseph Garvin

1
Le reproche classique est l'algorithme std :: sort. Std :: sort est plus rapide que n'importe quel algorithme de tri en C - la seule façon d'obtenir les mêmes performances en C est de le coder en dur partout où vous voulez ou d'utiliser des macros - et même alors le compilateur a moins d'informations à optimiser.
Arafangion

1

Avec les compilateurs d'optimisation modernes, il est très peu probable qu'un programme C pur soit beaucoup plus rapide que le code .net compilé, voire pas du tout. Avec l'amélioration de la productivité que les frameworks comme .net fournissent au développeur, vous pouvez faire des choses en une journée qui prenait habituellement des semaines ou des mois en C. régulier Couplé avec le coût bon marché du matériel par rapport au salaire d'un développeur, il est tout de même beaucoup moins cher d'écrire les trucs dans un langage de haut niveau et lancer du matériel à n'importe quelle lenteur.

La raison pour laquelle Jeff et Joel parlent de C comme étant le "vrai programmeur" est parce qu'il n'y a pas de main dans C. Vous devez allouer votre propre mémoire, désallouer cette mémoire, faire vos propres vérifications de limites, etc. Il n'y a rien de tel comme nouvel objet (); Il n'y a pas de garbage collection, de classes, de POO, de structures d'entités, de LINQ, de propriétés, d'attributs, de champs ou quoi que ce soit de ce genre. Vous devez savoir des choses comme l'arithmétique des pointeurs et comment déréférencer un pointeur. Et, d'ailleurs, sachez et comprenez ce qu'est un pointeur. Vous devez savoir ce qu'est un cadre de pile et quel est le pointeur d'instruction. Vous devez connaître le modèle de mémoire de l'architecture CPU sur laquelle vous travaillez. Il y a beaucoup de compréhension implicite de l'architecture d'un micro-ordinateur (généralement lemicro-ordinateur sur lequel vous travaillez) lors de la programmation en C qui n'est tout simplement pas présent ni nécessaire lors de la programmation en quelque chose comme C # ou Java. Toutes ces informations ont été déchargées sur le programmeur du compilateur (ou VM).


«Thow more hardware at the problem» ne fonctionne que dans les environnements où c'est réellement possible. Le marché intégré est un parfait contre-exemple (et c'est un marché massif ).
Bob Somers

Jeff et Joel blog uniquement sur les systèmes d'entreprise, pas sur les systèmes embarqués, il est donc raisonnable de supposer que c'est le contexte dans lequel cette question a été posée.
Robert C.Barth

1) Le code .net fonctionne aussi vite que le code C? Avez-vous déjà écrit un programme C? 2) La mentalité de "jeter plus de matériel sur le problème" est la raison pour laquelle ma machine à double cœur de 2 Go à 1,3 GHz peut à peine suivre Windows XP tandis que ma machine à 800 MHz à 512 Mo vole avec la dernière version d'Ubuntu.
Robert Gamble

Oui, j'ai écrit C. Ce n'est pas aussi glorieux que les gens le prétendent. Et les projets coûtent trop cher. C'est un cas simple d'économie. J'ai exécuté Win2k sur un Pentium Pro 180 MHz avec 768 Mo de RAM pendant des années en tant que serveur de messagerie et Web. Ça s'est très bien passé. Les preuves anecdotiques ne signifient rien.
Robert C.Barth

C n'est pas "glorieux" mais c'est rapide, j'ai écrit suffisamment de code C et C # pour savoir que C est presque toujours beaucoup plus rapide que C # tout en effectuant la même tâche. Pour certaines tâches, le développement dans des langages de niveau supérieur prend plus de temps, mais il s'agit d'utiliser le bon outil pour le travail et parfois c'est C.
Robert Gamble

1

C'est la différence entre automatique et manuel, les langues de niveau supérieur sont des abstractions ainsi automatisées. C / C ++ sont contrôlés et manipulés manuellement, même le code de vérification des erreurs est parfois un travail manuel.

C et C ++ sont également des langages compilés, ce qui signifie que rien de tout cela ne fonctionne partout, ces langages doivent être affinés pour le matériel avec lequel vous travaillez, ajoutant ainsi une couche supplémentaire de gotcha. Bien que cela devienne légèrement flou maintenant, les compilateurs C / C ++ devenant plus courants sur toutes les plates-formes. Vous pouvez effectuer des compilations croisées entre plates-formes. Ce n'est toujours pas une situation qui s'exécute partout, vous demandez essentiellement au compilateur A de compiler avec le même code différent du compilateur B.

Les langages C ne sont pas censés être faciles à comprendre ou à raisonner, c'est aussi pourquoi ils sont appelés langages systèmes. Ils sont sortis avant toutes ces bêtises d'abstraction de haut niveau. C'est aussi pourquoi ils ne sont pas utilisés pour la programmation Web frontale. Ils ne sont tout simplement pas adaptés à la tâche, leur moyen de résoudre des problèmes complexes qui ne peuvent pas être résolus avec l'outillage de langage conventionnel.

C'est pourquoi vous obtenez des trucs fous comme (micro-architectures, pilotes, physique quantique, AAA Games, systèmes d'exploitation) il y a des choses pour lesquelles le C et le C ++ sont bien adaptés. La vitesse et le nombre croquant étant les domaines principaux.



1

Il y a plusieurs raisons, notamment:

  • Il se compile en langage assembleur.
  • Il est typé statiquement.
  • Pas de collecte des ordures.
  • Aucune gestion d'erreur.
  • De nombreux langages de programmation ajoutent de nouvelles fonctionnalités. Une partie de la philosophie de C est de garder les choses simples au lieu d'ajouter plus de fonctionnalités.

Pourquoi devrait-il être plus rapide parce qu'il n'est pas orienté objet?
sb27

A) la programmation orientée objet crée un besoin de récupération de place, B) les grandes fonctionnalités comme la programmation orientée objet ajoutent de la complexité au compilateur,
Sapphire_Brick

A) Non. Voir C ++ ou Rust. B) Oui, mais cela donne également au compilateur des opportunités de nouvelles optimisations.
sb27

A) Rust a un garbage collection au moment de la compilation, et c ++ a un garbage collection pour les classes, c'est pourquoi il a des destructeurs, B) la complexité optimisée est toujours de la complexité
Sapphire_Brick

A) Ce n'est pas du ramasse-miettes, la gestion de la mémoire doit être faite même si vous faites votre programme dans l'assembly B) Non. Plus d'abstraction permet à l'optimiseur de faire de meilleures hypothèses.
sb27
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.