217 votes

Pourquoi le C est-il si rapide, et pourquoi les autres langages ne sont-ils pas aussi rapides, voire plus rapides ?

En écoutant le podcast de StackOverflow, on entend constamment dire que les "vrais programmeurs" écrivent en C, et que le C est tellement plus rapide parce qu'il est "proche de la machine". Laissant la première affirmation pour un autre billet, qu'est-ce qui est spécial au C qui lui permet d'être plus rapide que les autres langages ? Ou dit autrement : qu'est-ce qui empêche d'autres langages d'être capables de compiler en un binaire qui tourne aussi vite que le C ?

7 votes

Pouvez-vous indiquer quelle émission en particulier a parlé de ça ? J'aimerais bien l'entendre.

2 votes

Je suis vraiment surpris de voir à quel point les réponses à cette question sont mauvaises (la plupart des réponses ignorent les différences fondamentales entre les langages compilés et interprétés, etc., je sais ce qu'est le JIT, etc.

0 votes

N'oubliez pas le langage d'assemblage. Rien n'est plus rapide ou plus compact que les exes assemblés en assembleur. L'assemblage est presque purement binaire, c'est donc sans conteste le langage le plus rapide.

211voto

coobird Points 70356

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

Les langages plus récents qui prennent en charge le collecte des déchets , typage dynamique et d'autres facilités qui permettent au programmeur d'écrire plus facilement des programmes.

Le problème est qu'il y a une surcharge de traitement supplémentaire qui dégrade les performances de l'application. Le 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 capable d'allouer de la mémoire et de la libérer pour éviter que la mémoire ne se détériore. fuites de mémoire et doit gérer le typage statique des variables.

Cela dit, de nombreux langages et plateformes, tels que Java (avec ses Machine virtuelle Java ) et .NET (avec son Common Language Runtime) ont amélioré les performances au fil des ans avec des avancées telles que compilation juste-à-temps qui produit du code machine natif à partir du bytecode pour obtenir de meilleures performances.

3 votes

La collecte des déchets peut être plus rapide que la gestion manuelle de la mémoire (pour les programmes à courte durée de vie et/ou disposant de beaucoup de mémoire). La GC permet une allocation simple et rapide, et le programme ne perd pas de temps à désallouer les choses.

2 votes

Les programmes C allouent et désallouent généralement la mémoire en fonction des besoins. C'est inefficace. Une bonne VM allouera et désallouera de grandes quantités de mémoire, ce qui permettra de réaliser des gains de performance importants dans de nombreux cas.

65 votes

Rien n'empêche un programme C d'effectuer la même allocation par morceaux et le même ramassage des déchets, si ce n'est qu'il est "difficile".

90voto

Il y a un compromis que les concepteurs de C ont fait. C'est à dire qu'ils ont pris la décision de faire passer la vitesse avant la sécurité. C ne sera pas

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

En Java, l'indexation d'un tableau nécessite l'appel d'une méthode dans la machine virtuelle, la vérification des liens et d'autres contrôles d'intégrité. Ce est valide et absolument parfaite parce que cela ajoute de la sécurité là où elle est nécessaire. Mais en C, même des choses assez triviales ne sont pas mises en sécurité. Par exemple, le C ne demande pas à memcpy de vérifier si les régions à copier se chevauchent. C'est pas conçu comme un langage pour programmer une application commerciale importante.

Mais ces décisions de conception sont pas de bogues dans le langage C . Ils le sont à dessein, car ils permettent aux compilateurs et aux auteurs de bibliothèques de tirer le maximum de performances de l'ordinateur. Voici l'esprit du C : comment le C Justification Ce document 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 réellement portables, le Comité n'a pas voulu forcer les programmeurs à écrire de manière portable, pour empêcher l'utilisation du C comme "assembleur de haut niveau" : la capacité d'écrire du code spécifique à la machine est l'une des forces du C.

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

  • Faites confiance au programmeur.
  • N'empêchez pas le programmeur de faire ce qui doit être fait.
  • Adoptez un langage simple et concis.
  • Fournir une seule façon d'effectuer une opération.
  • Faites en sorte qu'il soit rapide, même si sa portabilité n'est pas garantie.

Le dernier proverbe nécessite une petite explication. Le potentiel de génération de code efficace est l'une des forces les plus importantes du C. Pour s'assurer 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 de la manière dont le matériel de la machine cible les effectue plutôt que par une règle générale abstraite. Un exemple de cette volonté de vivre avec ce que fait la machine peut être vu dans les règles qui régissent l'élargissement des objets char pour l'utilisation dans les expressions : si les valeurs des objets char s'élargissent en quantités signées ou non signées dépend typiquement de l'opération d'octet la plus efficace sur la machine cible.

1 votes

Donc en théorie, vous dites que si un autre langage avait une option "compiler sans filet de sécurité", il pourrait compiler jusqu'à quelque chose d'aussi rapide que le C ?

0 votes

Je ne parle pas de règles logiques comme ça :) mais en effet, toutes les vérifications ralentissent. Quand c'est justifié, les vérifications sont bonnes. Quand ça ne l'est pas, alors les vérifications ne sont pas la bonne chose. De plus, les performances dépendent des implémentations. Les langages ne peuvent qu'imposer des contraintes ou donner des libertés.

54 votes

Le C vérifie le déréférencement des pointeurs nuls en se plantant violemment :-). Il vérifie aussi occasionnellement les index de tableaux hors de portée et les variables non initialisées en bousillant vos trames de pile et vos données. Malheureusement, il les vérifie au moment de l'exécution.

78voto

JosephStyons Points 21187

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 que cela s'exécute en 0,10 seconde, alors le C est-il vraiment plus rapide ?

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

Bien que les compilateurs soient très intelligents, ils ne sont pas encore capables d'élaborer de manière créative un code qui rivalise avec des algorithmes manipulés à la main (en supposant que les "mains" appartiennent à une bon Programmeur C).

Edit :

De nombreux commentaires sont du type "J'écris en C et je ne pense pas aux optimisations".

Mais pour prendre un exemple précis de ce poste :

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 C j'écris 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 concernant l'implémentation auxquelles je ne pense pas dans la version Delphi. Comment une chaîne de caractères est-elle implémentée ? Dans Delphi, je ne le vois pas. En C, j'ai décidé que ce serait un pointeur vers un tableau d'entiers ASCII, que nous appelons chars. En C, nous testons l'existence des caractères 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 genre de décisions de bas niveau toutes les quelques lignes de code. Cela s'ajoute à un exécutable fait à la main, optimisé à la main.

48 votes

Pour être juste, il n'y a pas grand chose qui prendrait un mois en C et qui ne prendrait qu'un jour en Java et qui ne prendrait que 0,05 seconde à exécuter (c'est-à-dire un petit programme).

0 votes

Votre premier point est bon, il faut généralement plus de temps pour programmer en C parce qu'il n'inclut pas les facilités de langage et de bibliothèque dont disposent tant de langages plus récents qui aident à rendre un programmeur si productif. Je fais pas Je suis cependant d'accord avec le reste de votre message.

14 votes

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

51voto

Rob Williams Points 6316

Je ne l'ai pas encore vu, alors je vais le dire : Le C a tendance à être plus rapide parce que presque tout le reste est écrit en C. .

Java est construit sur C, Python est construit sur C (ou Java, ou .NET, etc.), Perl l'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 encore écrites en langage Assembleur, qui a tendance à être encore plus rapide. De plus en plus de choses sont écrites en quelque chose d'autre, qui est lui-même écrit en C.

Chaque instruction que vous écrivez dans d'autres langages (pas l'Assembleur) est typiquement 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 le C, ces instructions supplémentaires requises en C ont tendance à se concentrer sur l'ajout de sécurité, la complexité et la gestion des erreurs. Ce sont souvent de bonnes choses, mais elles ont un effet négatif sur la sécurité. coût et ses noms sont vitesse et taille .

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

Comment puis-je avoir le beurre et l'argent du beurre ? Comment puis-je m'amuser avec des abstractions de haut niveau dans mon langage préféré, puis descendre dans le détail du C pour plus de rapidité ?

Après quelques années de recherche, ma réponse est Python (sur C). Vous pouvez y jeter un coup d'oeil. À propos, vous pouvez également passer de Python à l'assemblage (avec l'aide d'une bibliothèque spéciale).

D'un autre côté, le mauvais code peut être écrit dans n'importe quel langage . Par conséquent, le code C (ou Assembleur) n'est pas automatiquement plus rapide. De même, certaines astuces d'optimisation peuvent apporter portions de code de langage de niveau supérieur proche 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, donc la différence n'a pas vraiment d'importance.

Profitez-en.

10 votes

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

3 votes

Dieu me préserve de remettre 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 qu'il soit de "plus haut niveau", qu'il ait plus de fonctionnalités, qu'il ait des contrôles de sécurité, etc. et qu'il soit donc plus lent que le C "équivalent".

3 votes

Jon : J'allais dire quelque chose de similaire, mais le point est en fait assez valable, car beaucoup de composants de base de la bibliothèque .NET sont en fait écrits en C et ont donc les limitations de vitesse de ce langage. Il sera intéressant de voir comment cela va évoluer à l'avenir.

37voto

Rob Allen Points 7768

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

qu'est-ce qui empêche d'autres langages d'être capables de compiler en un binaire qui tourne aussi vite que le C ?

En un mot, l'abstraction.

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

En général, plus les jouets du programmeur sont nombreux (types de données complexes, etc.), plus on s'éloigne du langage machine et plus la traduction doit être effectuée.

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

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

3 votes

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

1 votes

Le code .net ne s'exécute pas dans une VM. Il s'exécute en tant qu'instructions natives sur la plate-forme du processeur sur lequel il est exécuté (32-bit x86, 64-bit x86, ou IA64).

11 votes

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

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