Por que o C é tão rápido e por que outros idiomas não são tão rápidos ou mais rápidos? [fechadas]

208

Ao ouvir o podcast StackOverflow, o jab continua aparecendo que "programadores reais" escrevem em C, e que C é muito mais rápido porque está "próximo à máquina". Deixando a afirmação anterior para outro post, o que há de especial no C que permite que ele seja mais rápido que em outros idiomas? Ou, de outra forma: o que impede outras linguagens de serem compiladas em binário que roda tão rápido quanto C?

Mike C.
fonte
6
Você pode listar qual programa em particular falou sobre isso? Eu adoraria ouvir isso.
Giovanni Galbo 7/01/09
2
Realmente surpreso com o quão mal esta pergunta é respondida (a maioria das respostas ignora as diferenças fundamentais entre linguagens compiladas e interpretadas, etc., eu sei sobre o JIT yada yada yada) e quantas pessoas estão se posicionando 'defendendo' sua linguagem favorita (o garoto FORTRAN precisa tomar uma pílula).
Tim Anel
Não esqueça a linguagem assembly. Nada é mais rápido ou mais compacto que os ex-montados na montagem. Assembly é quase um binário puro, portanto, sem viés, o idioma mais rápido.
KKZiomek
3
C é o mais rápido porque é a velocidade da luz e a relatividade?
Conheça Taraviya
Obviamente, é errado que C seja a linguagem de programa mais rápida. Nenhuma linguagem de programa de qualquer tipo se aproxima da velocidade da FORTH. FORTH é usado para acionar bombas nucleares, é a linguagem de programa na maioria dos satélites, a principal linguagem de programa na Estação Espacial Internacional e também no CERN e no ITER. Eu estava comparando a velocidade entre o Microsoft C (versões diferentes) e a FORTH. YAWN para C ...
Scoobeedo Arrefecer

Respostas:

200

Não há muita coisa especial sobre C. Essa é uma das razões pelas quais é rápido.

Idiomas mais novos que oferecem suporte à coleta de lixo , digitação dinâmica e outras facilidades que facilitam a criação de programas pelo programador.

O problema é que há uma sobrecarga de processamento adicional que prejudicará o desempenho do aplicativo. C não possui nada disso, o que significa que não há sobrecarga, mas significa que o programador precisa ser capaz de alocar memória e liberá-las para evitar vazamentos de memória e deve lidar com a digitação estática de variáveis.

Dito isto, muitas linguagens e plataformas, como Java (com sua Java Virtual Machine ) e .NET (com seu Common Language Runtime) melhoraram o desempenho ao longo dos anos com avanços como a compilação just-in-time que produz código de máquina nativo a partir de bytecode para obter maior desempenho.

coobird
fonte
3
a coleta de lixo pode ser mais rápida que o gerenciamento manual de memória (para programas de curta duração e / ou muita memória). O GC permite uma alocação simples e rápida, e o programa não gasta tempo desalocando as coisas.
Kornel
2
Os programas C geralmente alocam e desalocam memória conforme necessário. Isso é ineficiente. Uma boa VM alocará e desalocará em grandes partes, gerando grandes ganhos de desempenho em muitos casos.
22410 skaffman
60
Não há nada impedindo um programa C de executar a mesma alocação em pedaços e coleta de lixo, além de ser "difícil".
ephemient
Muito bem dito, mas como Rob Allen disse, C também fornece menos abstração que Java ou .NET, resultando em menos tradução (o que é menos verdadeiro atualmente devido à compilação just-in-time (JIT) como você disse)
Gab Royer
5
porneL, gestão e sensatas alocações manuais sempre irá superar qualquer sistema GC quando usado corretamente e um monte de atenção é dada, você tem conhecimento absoluto sobre seus padrões de uso, o GC não faz, além de sistemas de GC adicionar sobrecarga
Ion Todirel
89

Há uma troca que os designers de C fizeram. Ou seja, eles tomaram a decisão de colocar a velocidade acima da segurança. C não

  • Verifique os limites do índice da matriz
  • Verifique se há valores de variável não inicializados
  • Verifique se há vazamentos de memória
  • Verifique se há dereferência de ponteiro nulo

Quando você indexa em uma matriz, em Java, são necessárias algumas chamadas de métodos na máquina virtual, verificação vinculada e outras verificações de integridade. Isso é válido e absolutamente correto , porque agrega segurança onde é devido. Mas em C, mesmo coisas bastante triviais não são colocadas em segurança. Por exemplo, C não exige que o memcpy verifique se as regiões a serem copiadas se sobrepõem. É não projetado como uma linguagem para programar uma aplicação de negócio grande.

Mas essas decisões de design são não erros na linguagem C . Eles são projetados, pois permitem que os compiladores e criadores de bibliotecas obtenham todo o desempenho do computador. Aqui está o espírito de C, como o documento C Rationale explica:

O código C pode não ser portátil. Embora se esforçasse para dar aos programadores a oportunidade de escrever programas verdadeiramente portáteis, o Comitê não queria forçar os programadores a escrever de maneira portável, para impedir o uso de C como um `` assembler de alto nível '': a capacidade de escrever específicos para máquinas código é um dos pontos fortes de C.

Mantenha o espírito de C. O Comitê manteve como objetivo principal preservar o espírito tradicional de C. Existem muitas facetas do espírito de C, mas a essência é um sentimento da comunidade dos princípios subjacentes nos quais a linguagem C se baseia. Algumas das facetas do espírito de C podem ser resumidas em frases como

  • Confie no programador.
  • Não impeça o programador de fazer o que precisa ser feito.
  • Mantenha o idioma pequeno e simples.
  • Forneça apenas uma maneira de executar uma operação.
  • Faça com que seja rápido, mesmo que não seja garantido que seja portátil.

O último provérbio precisa de uma pequena explicação. O potencial para geração eficiente de código é um dos pontos mais importantes de C. Para ajudar a garantir que nenhuma explosão de código ocorra para o que parece ser uma operação muito simples, muitas operações são definidas como o hardware da máquina de destino, em vez de: uma regra abstrata geral. Um exemplo dessa vontade de viver com o que a máquina faz pode ser visto nas regras que governam o alargamento de objetos char para uso em expressões: se os valores dos objetos char se expandem para quantidades assinadas ou não assinadas normalmente depende de qual operação de bytes é mais eficiente na máquina de destino.

Johannes Schaub - litb
fonte
51
C verifica o ponteiro nulo deref travando violentamente :-). Ocasionalmente, também verifica índices de matriz fora do intervalo e variáveis ​​não inicializadas, estragando os quadros e dados da pilha. Infelizmente, verifica-os em tempo de execução.
214
18
Eu não diria que C não é seguro, o que soa como o que você está sugerindo. Assume que você não é um idiota. Se você apontar uma arma para baixo e atirar em seu próprio pé, C agradecerá com satisfação e permitirá que você faça isso, pois assume que você é mais esperto do que é. Isso não é necessariamente uma coisa ruim.
7269 Bob Somers
19
@ Bob: Exatamente. Dizer C não é seguro porque permite fazer coisas perigosas é como dizer que um carro não é seguro porque permitirá que você saia de um penhasco. C é tão seguro quanto a pessoa que dirige (mas há muitos motoristas inseguros por aí).
Robert Gamble
5
Bob, cometer erros como saturação de buffer não significa que você é um idiota. Significa apenas que você ainda é humano. Eu percebo que C e C ++ não é ruim (eu gosto muito deles).
Johannes Schaub - litb
4
O @ JohannesSchaub-litb C é perfeito para programação de aplicativos em larga escala. Se se encontra que é difícil fazer projetos maiores do que um Olá mundo, então o problema é com o programador, não com a língua ...
75

Se você gasta um mês para criar algo em C que é executado em 0,05 segundos, e eu passo um dia escrevendo a mesma coisa em Java e em 0,10 segundos, C é realmente mais rápido?

Mas, para responder à sua pergunta, o código C bem escrito geralmente será executado mais rapidamente do que o código bem escrito em outros idiomas, porque parte da escrita "bom" do código C inclui otimizações manuais no nível da máquina.

Embora os compiladores sejam realmente muito inteligentes, eles ainda não são capazes de criar códigos que competem com algoritmos de massagem manual (supondo que as "mãos" pertençam a um bom programador C).

Editar:

Muitos comentários são do tipo "eu escrevo em C e não penso em otimizações".

Mas, para pegar um exemplo específico deste post :

Em Delphi, eu poderia escrever isso:

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;

e no CI escreva isto:

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 */
   }
}

Mas quantas otimizações existem na versão C? Tomamos muitas decisões sobre implementação que não penso na versão Delphi. Como uma string é implementada? Em Delphi, eu não vejo isso. Em C, decidi que seria um ponteiro para uma matriz de números inteiros ASCII, que chamamos de caracteres. Em C, testamos a existência de um personagem de cada vez. No Delphi, eu uso o Pos.

E este é apenas um pequeno exemplo. Em um programa grande, um programador C precisa tomar esse tipo de decisão de baixo nível com todas as poucas linhas de código. Ele adiciona um executável artesanal, otimizado à mão.

JosephStyons
fonte
45
Para ser justo, porém, não há muito que levaria um mês em C que levaria apenas um dia em Java que leva apenas 0,05 segundos para executar (ou seja, programa pequeno).
dreamlax
12
Programei em C há anos e quase nunca preciso fazer nenhum dos tipos de otimizações que você sugere. Eu tenho portado vários programas para C (principalmente do Perl) e geralmente vejo um aumento de velocidade de mais de 10x e uma redução significativa no uso de memória sem nenhuma otimização codificada manualmente.
Robert Gamble
1
É claro que há algumas coisas que podem demorar consideravelmente mais para se programar em C devido à falta de instalações existentes, portanto é uma troca entre desempenho do computador e desempenho do programador (entre outras coisas), e é por isso que nem todos programamos tudo em C.
Robert Gamble
4
Criei programas em C ++ que processam milhares de linhas de dados em menos tempo do que os programas Java ou .NET podem ser iniciados. É uma das frustrações que tenho com as línguas mais modernas. C é ótimo para programas lean que precisam de requisitos mínimos de tempo de execução. PowerBasic também é ótimo para isso.
bruceatk
35
Você está dizendo que um programa que leva um mês em C e é duas vezes mais rápido que um programa escrito em Java que leva apenas um dia para escrever não vale a pena? E se esse programa precisar executar mais de 500.000.000 de vezes por dia? Ser duas vezes mais rápido é incrivelmente significativo. Se for executado em milhares ou milhões de CPUs, a economia de custos do mês extra de desenvolvimento para atingir o dobro do desempenho será enorme. Basicamente, você precisa conhecer / entender a escala de sua implantação antes de escolher a plataforma de desenvolvimento.
Nicerobot
49

Eu não vê-lo já, então eu vou dizer: C tende a ser mais rápido porque quase tudo é escrito em C .

Java é construído em C, Python é construído em C (ou Java ou .NET etc.), Perl é etc. O sistema operacional é escrito em C, as máquinas virtuais são escritas em C, os compiladores são escritos em C, os intérpretes são escritos em C. Algumas coisas ainda estão escritas na linguagem Assembly, que tende a ser ainda mais rápida. Mais e mais coisas estão sendo escritas em outra coisa, que é escrita em C.

Cada instrução que você escreve em outros idiomas (não no Assembly) geralmente é implementada como várias instruções em C, que são compiladas no código de máquina nativo. Como esses outros idiomas tendem a existir para obter um nível de abstração mais alto que C, essas instruções extras necessárias em C tendem a se concentrar em adicionar segurança, adicionar complexidade e fornecer tratamento de erros. Geralmente, essas são coisas boas, mas têm um custo e seus nomes são velocidade e tamanho .

Pessoalmente, escrevi literalmente dezenas de idiomas, abrangendo a maior parte do espectro disponível, e pessoalmente busquei a mágica que você sugere:

Como posso comer meu bolo e também? Como posso brincar com abstrações de alto nível no meu idioma favorito e depois descer para o âmago da questão de velocidade C?

Após alguns anos de pesquisa, minha resposta é Python (em C). Você pode querer dar uma olhada. A propósito, você também pode ir para o Assembly a partir do Python (com alguma ajuda menor de uma biblioteca especial).

Por outro lado, o código incorreto pode ser escrito em qualquer idioma . Portanto, o código C (ou montagem) não é automaticamente mais rápido. Da mesma forma, alguns truques de otimização podem aproximar partes do código de linguagem de nível mais alto do nível de desempenho do C. bruto.

Aproveitar.

Rob Williams
fonte
10
Isso realmente não se aplica a idiomas compilados por JIT. Não é como se meu C # estivesse sendo compilado para IL, que é traduzido para C, que é compilado para código de máquina. Não, o IL é compilado pelo JIT - e a linguagem de implementação do JIT é irrelevante nesse ponto. É apenas a produção de código de máquina.
Jon Skeet
3
Deus proíba que eu deva questionar o lendário Jon Skeet, mas parece inteiramente relevante que o código da máquina que está sendo produzido seja para C # em vez de C, por isso é "nível superior", tem mais funcionalidade, tem verificações de segurança, etc. e ser, consequentemente, mais lento do que o "equivalente" C.
Rob Williams
3
@ Jon: Eu estava prestes a dizer algo semelhante, mas o ponto é realmente um pouco válido, porque muitos dos componentes principais da biblioteca .NET são realmente escritos em C e, portanto, têm limitações de velocidade em C. Será interessante ver como isso vai mudar no futuro.
Konrad Rudolph
1
Isso parece errado, outros compiladores / intérpretes / vms de linguagem são frequentemente, mas nem sempre, escritos em c (ou pelo menos para a camada mais baixa) porque c é bem rápido (e em muitos casos o mais rápido).
Roman A. Taycher
2
Esta resposta não é verdadeira. Como apontado acima, ele não se aplica a idiomas JIT, mas também não se aplica a idiomas com seus próprios compiladores (que, se um esforço extraordinário fosse colocado neles, poderiam gerar código mais rápido que os compiladores C modernos). A única outra classe de idiomas restantes são os idiomas interpretados, e esses não são mais lentos que C apenas porque são escritos em C, mas porque são a sobrecarga da interpretação, não importa como você o fatie e mesmo que o intérprete tenha sido escrito em assembly. , é enorme.
Score_Under
38

Existem muitas perguntas - principalmente as que não estou qualificado para responder. Mas para este último:

o que impede outras linguagens de serem compiladas em binário que roda tão rápido quanto C?

Em uma palavra, abstração.

C está a apenas um ou dois níveis de abstração da linguagem de máquina. As linguagens Java e .Net estão em um mínimo de 3 níveis de abstração do assembler. Não tenho certeza sobre Python e Ruby.

Normalmente, quanto mais brinquedos programadores (tipos de dados complexos, etc.), mais longe você está da linguagem de máquina e mais tradução precisa ser feita.

Estou aqui e ali, mas essa é a essência básica.

Atualização ------- Existem bons comentários neste post com mais detalhes.

Rob Allen
fonte
3
Tecnicamente, Java e .Net são infinitamente abstraídos da linguagem da máquina em que são executados. Eles são executados em VMs. Mesmo com o JIT, o código original precisa ser massivamente massificado para obter algo parecido com o código de máquina nativo.
jmucchiello
1
O código .net não é executado em uma VM. Ele é executado como instruções nativas em qualquer plataforma de processador em que está sendo executado (x86 de 32 bits, x86 de 64 bits ou IA64).
22380 Robert C. Barth
11
@ Robert: .net faz usar uma VM. O código .net é compilado no bytecode, que é executado pela VM. A VM converte o bytecode em instruções nativas em tempo de execução.
Robert Gamble
3
É muito importante observar que Java e outras abstrações da linguagem OO afetaram os conjuntos de instruções do processador. Os processadores mais novos têm instruções para acelerar a execução do Java se a VM Java souber sobre essas otimizações e usá-las. Não é enorme, mas é útil.
Adam Davis
1
Talvez ThumbEE pt.wikipedia.org/wiki/…
Roman A. Taycher
35

Não é tão rápido que C seja rápido quanto o modelo de custo de C seja transparente . Se um programa C é lento, é lento de uma maneira óbvia: executando várias instruções. Comparado com o custo das operações em C, operações de alto nível em objetos (especialmente reflexão) ou seqüências de caracteres podem ter custos que não são óbvios.

Duas linguagens que geralmente compilam em binários que são tão rápidos quanto C são o ML padrão (usando o compilador MLton ) e o Objective Caml . Se você verificar o jogo de benchmarks, verá que, para alguns benchmarks, como árvores binárias, a versão do OCaml é mais rápida que C. (não encontrei nenhuma entrada do MLton.) Mas não leve o jogo muito a sério; como diz um jogo, os resultados geralmente refletem quanto esforço as pessoas dedicam ao ajuste do código.

Norman Ramsey
fonte
É possível escrever código não-obviamente caro em qualquer idioma. É que, em algumas línguas, você deve escrever uma variante interna do Lisp ou Forth primeiro ...
Donal Fellows
Também Rust corresponde a C nos benchmarks.
stark
18

C nem sempre é mais rápido.

C é mais lento do que, por exemplo, o Modern Fortran.

C é geralmente mais lento que Java para algumas coisas. (Especialmente depois que o compilador JIT analisou seu código)

C permite que o alias do ponteiro aconteça, o que significa que algumas boas otimizações não são possíveis. Especialmente quando você tem várias unidades de execução, isso causa interrupções na busca de dados. Ow.

A suposição de que a aritmética do ponteiro funciona realmente causa um desempenho lento em algumas famílias de CPU (PIC particularmente!).

Basicamente, quando você obtém uma unidade vetorial ou um compilador paralelo, o C fede e o Fortran moderno roda mais rápido.

Os truques do programador C como thunking (modificando o executável em tempo real) causam paradas de pré-busca da CPU.

Você entendeu?

E nosso bom amigo, o x86, executa um conjunto de instruções que hoje em dia tem pouca relação com a arquitetura real da CPU. Registros sombra, otimizadores de armazenamento de carga, tudo na CPU. Então, C está próximo ao metal virtual. O verdadeiro metal, a Intel não deixa você ver. (Historicamente, as CPUs VLIW foram um pouco difíceis, talvez isso não seja tão ruim.)

Se você programar em C em um DSP de alto desempenho (talvez um DSP da TI?), O compilador precisará fazer algumas coisas complicadas para desenrolar o C nas várias unidades de execução paralela. Portanto, nesse caso, C não está perto do metal, mas está perto do compilador, que fará a otimização de todo o programa. Esquisito.

E, finalmente, algumas CPUs (www.ajile.com) executam bytecodes Java em hardware. C usaria uma PITA para usar nessa CPU.

Tim Williscroft
fonte
1
Quando foi a última vez que thunking foi escrito, em C? X86 moderna é uma interface para um projeto em sua maioria RISC, mas que tem pouco a ver com VLIW ...
Calyth
7
Grande parte do seu post ignora a existência do C99. Além disso, muitos compiladores C / C ++ oferecem a palavra-chave restrita C99 (garante que não haja alias do ponteiro) como uma extensão.
Evan Teran
Presumo que todos estejam seguindo / fazendo a transição para seguir o top 25 da CWE / SANS e evitando fazer novos designs em C. Portanto, não há campos verdes C, tão pouco quanto nenhum C99.
Tim Williscroft 20/01/2009
2
Você poderia mostrar um exemplo quando c é mais lento que o Fortenberry moderno?
Adam
Não sei se houve um tempo em que os compiladores C competiram muito bem com os melhores compiladores Fortran. É claro que há muito código que você não gostaria de escrever no FORTRAN 77 (muito menos 66), mas os padrões mais recentes do Fortran têm sido cada vez mais agradáveis.
TFB
11

o que impede outras linguagens de serem compiladas em binário que roda tão rápido quanto C?

Nada. Linguagens modernas como Java ou .NET langs são mais orientadas à produtividade do programador do que ao desempenho. O hardware é barato hoje em dia. Além disso, a compilação para representação intermediária oferece muitos bônus, como segurança, portabilidade etc. O .NET CLR pode tirar proveito de diferentes hardwares - por exemplo, você não precisa otimizar / recompilar manualmente o programa para usar o conjunto de instruções SSE.

aku
fonte
eu argumentaria a portabilidade aqui. Se você quiser um código realmente portátil, você o escreverá em C e não em qualquer outro idioma. Temos um código em execução em cerca de 25 sistemas operacionais. A partir dos e ThreadX e acabamento em Linux / XP me mostrar uma outra língua que pode fazer isso :)
Ilya
1
@Ilya eu discordo. É fácil escrever código não portátil em C. Veja como foi doloroso para alguns portar para 64 bits. Os idiomas de bytecode podem funcionar em várias plataformas se você tiver o intérprete de bytecode certo.
Calyth
1
@IIya, o código C portátil é mais uma exceção do que uma regra. Eu portava o código C entre diferentes plataformas de hardware / software e sei que é um pesadelo.
aku
Mesmo para a palavra PC, não é o caso. Examine a realidade da maioria dos aplicativos de plataforma cruzada escritos em c / c ++, um pouco em java. Para o desenvolvimento de baixo nível incorporado, não há outros casos. C é a linguagem mais portátil de fato.
Ilya
@aku -> PORTING código ruim pode ser um desastre, eu concordo. Escrever código portátil no ADVANCE - C é a melhor opção. Eu diria que C ++ é uma opção, mas indo para a plataforma incorporada você sempre encontrará um compilador C decente, para c ++ você pode se achar sem compilador.
Ilya
8

Os principais fatores são que é uma linguagem de tipo estatístico e compilada no código de máquina. Além disso, como é um idioma de baixo nível, geralmente não faz nada que você não solicite.

Esses são outros fatores que vêm à mente.

  • Variáveis ​​não são inicializadas automaticamente
  • Sem verificação de limites em matrizes
  • Manipulação de ponteiro não verificada
  • Nenhuma verificação de estouro inteiro
  • Variáveis ​​de tipo estático
  • As chamadas de função são estáticas (a menos que você use ponteiros de função)
  • Os escritores do compilador tiveram muito tempo para melhorar o código de otimização. Além disso, as pessoas programam em C com o objetivo de obter o melhor desempenho, então há pressão para otimizar o código.
  • Partes da especificação de linguagem são definidas pela implementação, portanto, os compiladores são livres para fazer as coisas da maneira mais ideal.

A maioria das linguagens de tipo estático pode ser compilada com a mesma rapidez ou rapidez que C, especialmente se elas podem fazer suposições que C não pode por causa de aliasing de ponteiro, etc.

Matthew Crumley
fonte
C de baixo nível? Eu acho que é um significado relativo agora, comparado ao Java sim, mas comparado ao assembly não. Bom post, me fez pensar.
Mark Mark
Você está certo, é definitivamente relativo. O que quero dizer é que ele está "próximo à máquina" e não ajuda a fazer coisas como gerenciamento de memória ou controlar os tamanhos de array.
Matthew Crumley
2
C é uma linguagem de baixo nível. C sempre foi uma linguagem de baixo nível. Você traduz manualmente o código C para o assembler sem muita dificuldade.
22380 Robert C. Barth
2
@ Robert: C costumava ser considerado uma linguagem de alto nível porque, comparada à montagem (o que era muito comum), era. É considerado um idioma de baixo nível em comparação com a maioria dos idiomas em uso atualmente.
Robert Gamble
Honestamente, esta é uma resposta muito tendenciosa. Porra, quase todos os programadores de C fazem verificação de limites, etc. No entanto, o C ainda é MUITO mais rápido que o C ++.
MarcusJ
8

Eu acho que você esqueceu que a linguagem Assembly também é uma linguagem :)

Mas, falando sério, os programas em C são mais rápidos apenas quando o programador sabe o que está fazendo. Você pode escrever facilmente um programa em C que seja mais lento que os programas escritos em outros idiomas que executam o mesmo trabalho.

A razão pela qual C é mais rápido é porque ele é projetado dessa maneira. Permite fazer várias coisas de "nível inferior" que ajudam o compilador a otimizar o código. Ou, digamos, você, o programador, é responsável por otimizar o código. Mas muitas vezes é bastante complicado e propenso a erros.

Outros idiomas, como outros já mencionados, concentram-se mais na produtividade do programador. Geralmente, acredita-se que o tempo do programador é muito mais caro que o tempo da máquina (mesmo nos velhos tempos). Portanto, faz muito sentido minimizar o tempo que os programadores gastam na gravação e depuração de programas, em vez do tempo de execução dos programas. Para fazer isso, você sacrificará um pouco o que pode fazer para tornar o programa mais rápido, porque muitas coisas são automatizadas.

PolyThinker
fonte
3
Embora se você escrevesse um programa uma vez em C e novamente no Assembly, a versão C provavelmente seria mais rápida porque o compilador é mais inteligente do que você.
Mk12 7/08
7

Na maioria das vezes, toda instrução C corresponde a muito poucas instruções do assembler. Você está essencialmente escrevendo código de máquina de nível superior, para ter controle sobre quase tudo o que o processador faz. Muitas outras linguagens compiladas, como C ++, possuem muitas instruções simples que podem se transformar em muito mais código do que você imagina (funções virtuais, construtores de cópias etc.). E linguagens interpretadas como Java ou Ruby têm outra camada de código. instruções que você nunca vê - a Máquina Virtual ou o Intérprete.

AShelly
fonte
E algumas dessas linguagens de alto nível orgulham-se de que são capazes de remover a maior parte do lixo adicionado em primeiro lugar. Coisas como eliminação de cópias, otimização do valor de retorno, mudança de construção / atribuição, etc. em C ++.
cmaster - reinstate monica
Portanto, tudo se resume ao número de instruções de montagem geradas a partir do código. Há mais instruções de montagem por linha de código de alto nível, mais o desempenho sofre?
ENDEESA
Isso pode ser uma simplificação excessiva, mas há uma relação direta entre o número de instruções de montagem e a velocidade do programa. Há um tempo mínimo para o processador executar cada instrução. IMHO, um idioma que permite entender facilmente quantas instruções você está escrevendo ajuda a escrever um código mais eficiente. (Existem outros custos de tempo do processador, como falhas de ramificação e cache, mas mesmo assim, menos abstração ajuda a esclarecer o que a CPU está fazendo).
AShelly
7

Eu sei que muitas pessoas disseram isso de uma maneira longa, mas:

C é mais rápido porque faz menos (para você).

Daemin
fonte
Este. Tão fiel ao espírito de C.
cmaster - reinstate monica
7

C ++ é mais rápido, em média (como era inicialmente, em grande parte um superconjunto de C, embora haja algumas diferenças). No entanto, para benchmarks específicos, geralmente há outro idioma que é mais rápido.

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

fannjuch-redux foi o mais rápido em Scala

n-bodye fastaforam mais rápidos em Ada.

spectral-norm foi o mais rápido em Fortran.

reverse-complement, mandelbrotE pidigitsforam os mais rápidos no ATS.

regex-dna foi o mais rápido em JavaScript.

chameneou-redux foi mais rápido o Java 7.

thread-ring foi o mais rápido em Haskell.

O restante dos benchmarks foi mais rápido em C ou C ++.

Peter Lawrey
fonte
"como é um conjunto de super C" - Não, C ++ é não um super conjunto de C
PP
1
extern "C"não tem nada a ver com C ++ ser um super conjunto de C.
PP
2
É como dizer que system("bash script.sh");funciona para qualquer script do bash e, portanto, C é um superconjunto do bash. extern "C"fornece a ligação C em C ++ devido à confusão de nomes. Enquanto chamar X como um superconjunto de Y significa que qualquer coisa que possa ser feita em Y também pode ser feita em X, o que não é verdade para C ++. Existem algumas construções de linguagem que são válidas em C, mas não em C ++.
19716 PP
1
@PP Não há nada no padrão C ++ que exija que bashseja um programa de linha de comando disponível. Se tivesse e incluísse qual versão / especificação do bash precisava ser suportada, consideraria superconjunto.
31816 Peter Lawrey
1
é trivialmente fácil escrever código C que não é código C ++, por exemplo:struct foo { int: this; }; typedef float foo;
315 Jasen
6

Muitas dessas respostas fornecem razões válidas para o fato de C ser ou não mais rápido (em geral ou em cenários específicos). É inegável que:

  • Muitos outros idiomas fornecem recursos automáticos que consideramos garantidos. A verificação de limites, a verificação do tipo em tempo de execução e o gerenciamento automático de memória, por exemplo, não são gratuitos. Há pelo menos algum custo associado a esses recursos, nos quais não podemos pensar - ou até perceber - ao escrever um código que usa esses recursos.
  • A etapa da origem para a máquina geralmente não é tão direta em outros idiomas como em C.
  • OTOH, dizer que o código C compilado é executado mais rapidamente que outro código escrito em outras linguagens é uma generalização que nem sempre é verdadeira. É fácil encontrar contra-exemplos (ou criar).

Apesar disso, há algo mais que notei que, penso, afeta o desempenho comparativo de C vs. muitos outros idiomas mais do que qualquer outro fator. A saber:

Outros idiomas geralmente facilitam a gravação de código que é executado mais lentamente. Muitas vezes, é até encorajado pelas filosofias de design da linguagem. Corolário: é mais provável que um programador C escreva código que não executa operações desnecessárias.

Como exemplo, considere um programa simples do Windows no qual uma única janela principal é criada. A versão AC preencheria uma WNDCLASS[EX]estrutura que seria passada para RegisterClass[Ex], depois chamaria CreateWindow[Ex]e inseriria um loop de mensagens. Código altamente simplificado e abreviado a seguir:

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);
}

Um programa equivalente em C # poderia ser apenas uma linha de código:

Application.Run(new Form());

Essa linha de código fornece toda a funcionalidade que quase 20 linhas de código C fizeram e adiciona algumas coisas que deixamos de fora, como a verificação de erros. A biblioteca mais rica e completa (em comparação com as usadas em um projeto C típico) trabalhou muito para nós, liberando nosso tempo para escrever muitos outros trechos de código que nos parecem curtos, mas envolvem muitos passos nos bastidores.

Mas uma rica biblioteca que permite o inchaço fácil e rápido do código não é realmente o meu ponto. Meu ponto de vista é mais aparente quando você começa a examinar o que realmente acontece quando nossa pequena linha de execução realmente é executada. Para se divertir, habilite o acesso à fonte .NET no Visual Studio 2008 ou superior e entre na linha simples acima. Uma das pequenas jóias divertidas que você encontrará é este comentário no getter para 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(); 
} 

Dez vezes . As informações aproximadamente equivalentes à soma do que é armazenado em uma WNDCLASSEXestrutura e do que é passado CreateWindowExsão recuperadas da Controlclasse dez vezes antes de serem armazenadas em uma WNDCLASSEXestrutura e repassadas para RegisterClassExe CreateWindowEx.

Em suma, o número de instruções executadas para executar esta tarefa muito básica é de 2 a 3 ordens de magnitude a mais em C # do que em C. Parte disso se deve ao uso de uma biblioteca rica em recursos, que é necessariamente generalizada versus nosso código C simples que faz exatamente o que precisamos e nada mais. Mas parte disso se deve ao fato de a natureza modularizada e orientada a objetos da estrutura .NET se prestar a muitas repetições de execução que geralmente são evitadas por uma abordagem processual.

Não estou tentando escolher C # ou o .NET framework. Também não estou dizendo que modularização, generalização, recursos de biblioteca / linguagem, OOP etc. são coisas ruins . Eu costumava fazer a maior parte do meu desenvolvimento em C, posteriormente em C ++ e, mais recentemente, em C #. Da mesma forma, antes de C, eu usava principalmente montagem. E a cada passo "mais alto" meu idioma aumenta, escrevo programas melhores, mais sustentáveis ​​e mais robustos em menos tempo. No entanto, eles tendem a executar um pouco mais devagar.

P Papai
fonte
2
Esse é um problema de API, não de idioma.
Arafangion
1
@Arafangion: Eu entendo o que você está dizendo, mas meio que erra o ponto. A biblioteca rica em recursos é ativada (e, de certa forma, exigida) pelo idioma rico em recursos. E não é apenas a biblioteca. A biblioteca é apenas um exemplo de uso comum do idioma. O código de aplicativo típico em qualquer idioma geralmente tem uma semelhança com as bibliotecas normalmente usadas nesse idioma. É realmente mais uma mentalidade promovida pelo idioma. Por exemplo, os idiomas OO geralmente gastam mais tempo alocando, construindo, destruindo e desalocando objetos do que os idiomas com menos suporte a OOP.
P papai
Admito que uma determinada escolha de linguagem geralmente implica uma plataforma e uma biblioteca em particular, e foi por isso que fiz esse comentário (para que o leitor estivesse mais ciente), mas dito isso, usar (por exemplo) C ++ no Windows é um besta muito diferente de, digamos, C ++ no linux e diferente novamente com C ++ no Android. Outro exemplo é o Python - temos CPython, Jython, PyPy e IronPython - todos os quais usam bibliotecas muito diferentes.
Arafangion
Mas, usando qualquer um desses Pythons, os desenvolvedores tendem a escrever aplicativos de uma certa maneira. Por exemplo, eles podem ler e gravar em um arquivo de texto, criando novos objetos com os dados que lêem. Em C, por outro lado, um desenvolvedor provavelmente faria uma alocação única de uma matriz de estruturas e leria e gravaria essas estruturas a partir de um arquivo binário. Obviamente, este é simplesmente um exemplo artificial que tenta ilustrar o ponto que estou tentando enfatizar sobre a mentalidade .
P papai
6

Eu não acho que alguém tenha mencionado o fato de que muito mais esforço foi colocado nos compiladores C do que em qualquer outro compilador, com talvez a exceção do Java.

O C é extremamente otimizado por muitos dos motivos já mencionados - mais do que quase qualquer outro idioma. Portanto, se a mesma quantidade de esforço for colocada em outros compiladores de idiomas, C provavelmente continuará no topo.

Acho que há pelo menos uma linguagem candidata que, com esforço, poderia ser otimizada melhor que C e, portanto, poderíamos ver implementações que produzem binários mais rápidos. Estou pensando no digital mars D, porque o criador teve o cuidado de criar uma linguagem que poderia ser melhor otimizada do que C. Pode haver outras linguagens com essa possibilidade. No entanto, não consigo imaginar que qualquer linguagem tenha compiladores mais do que apenas alguns por cento mais rápidos que os melhores compiladores C. Eu adoraria estar errado.

Eu acho que a verdadeira "fruta baixa" estará em idiomas projetados para facilitar a otimização dos seres humanos. Um programador experiente pode tornar qualquer linguagem mais rápida - mas às vezes você precisa fazer coisas ridículas ou usar construções não naturais para fazer isso acontecer. Embora sempre exija esforço, uma boa linguagem deve produzir código relativamente rápido sem ter que ficar obcecado com a maneira exata como o programa foi escrito.

Também é importante (pelo menos para mim) que o código do pior caso tenda a ser rápido. Existem inúmeras "provas" na Web de que o Java é tão rápido ou mais rápido que o C, mas isso se baseia em exemplos de seleção de cereja. Não sou muito fã de C, mas sei que QUALQUER COISA que escrevo em C vai correr bem. Com o Java, "provavelmente" será executado dentro de 15% da velocidade, geralmente dentro de 25%, mas em alguns casos pode ser muito pior. Todos os casos em que é tão rápido ou dentro de alguns por cento geralmente são devidos à maior parte do tempo gasto no código da biblioteca, que é C altamente otimizado de qualquer maneira.

Don
fonte
5

Na verdade, isso é um pouco de falsidade perpetuada. Embora seja verdade que os programas C são frequentemente mais rápidos, nem sempre é esse o caso, especialmente se o programador C não for muito bom nisso.

Um grande buraco evidente que as pessoas tendem a esquecer é quando o programa precisa bloquear algum tipo de IO, como a entrada do usuário em qualquer programa da GUI. Nesses casos, não importa realmente qual idioma você usa, pois você está limitado pela taxa na qual os dados podem chegar, e não pela rapidez com que é possível processá-los. Nesse caso, não importa muito se você estiver usando C, Java, C # ou mesmo Perl; você simplesmente não pode ir mais rápido do que os dados podem entrar.

A outra coisa importante é que o uso da coleta de lixo e o não uso de ponteiros adequados permitem que a máquina virtual faça várias otimizações não disponíveis em outros idiomas. Por exemplo, a JVM é capaz de mover objetos na pilha para desfragmentá-la. Isso torna as alocações futuras muito mais rápidas, pois o próximo índice pode ser simplesmente usado, em vez de procurá-lo em uma tabela. As JVMs modernas também não precisam desalocar a memória; em vez disso, eles apenas movem os objetos ativos quando o GC e a memória gasta dos objetos mortos são recuperados essencialmente de graça.

Isso também traz um ponto interessante sobre C e mais ainda em C ++. Existe uma filosofia de design como "Se você não precisa, não paga". O problema é que, se você quiser, acaba pagando pelo nariz. Por exemplo, a implementação da vtable em Java tende a ser muito melhor do que as implementações em C ++, portanto, as chamadas de funções virtuais são muito mais rápidas. Por outro lado, você não tem escolha a não ser usar funções virtuais em Java e elas ainda custam algo, mas em programas que usam muitas funções virtuais, o custo reduzido aumenta.

James
fonte
1
"a implementação da vtable em Java tende a ser muito melhor do que as implementações em C ++, portanto, as chamadas de funções virtuais são muito mais rápidas.". Como diabos você pode ir mais rápido que o MOV EAX, [ECX]; CHAMADA [EAX + algum índice]; ? A menos que você possa chamar uma função sem procurá-la, isso parece ótimo.
Frans-Willem
@Frans - um compilador JIT (como o Java HotSpot) pode alinhar a pesquisa da vtable se determinar que um determinado objeto é sempre de um determinado tipo. O C ++ também fará isso se souber as mesmas informações em tempo de compilação, mas é mais fácil fazer essa otimização com bytecode Java do que com as instruções da máquina x86.
Tom
6
@ James - Argumentar "E / S torna o desempenho menos importante" não invalida a afirmação "C é mais rápido que em outros idiomas". Não é um buraco gritante, é um argumento de palha.
Tom
Teria sido melhor usar o tratamento de string de C (e também a biblioteca C padrão) como exemplo, pois essa é uma área em que C é ruim. A maioria dos outros idiomas se sai melhor, mesmo com o código inicial simplista.
Donal Fellows
@DonalFellows as funções mem * podem ser mais rápidas que as funções str * em algumas tarefas, mas o tratamento de strings é eficiente se for tomado cuidado. você tem uma referência específica em mente?
Jasen
4

Não se trata tanto da linguagem quanto das ferramentas e bibliotecas. As bibliotecas e compiladores disponíveis para C são muito mais antigos do que para idiomas mais novos. Você pode pensar que isso os tornaria mais lentos, mas au contraire.

Essas bibliotecas foram gravadas em um momento em que o poder de processamento e a memória eram muito importantes. Eles precisavam ser escritos com muita eficiência para funcionar. Os desenvolvedores de compiladores C também tiveram muito tempo para trabalhar em todos os tipos de otimizações inteligentes para diferentes processadores. A maturidade e a ampla adoção de C proporcionam uma vantagem significativa em relação a outros idiomas da mesma idade. Ele também oferece a C uma vantagem de velocidade em relação às ferramentas mais recentes que não enfatizam o desempenho bruto tanto quanto o C precisava.

Dave Swersky
fonte
4

A falta de abstração é o que torna C mais rápido. Se você escreve uma declaração de saída, sabe exatamente o que está acontecendo. Se você escrever uma instrução de saída em java, ela será compilada em um arquivo de classe que será executado em uma máquina virtual, introduzindo uma camada de abstração. A falta de recursos orientados a objetos como parte da linguagem também aumenta sua velocidade, com menos código sendo gerado. Se você usa C como uma linguagem orientada a objetos, está fazendo toda a codificação para coisas como classes, herança, etc. Isso significa, em vez disso, tornar algo generalizado o suficiente para todos com a quantidade de código e a penalidade de desempenho que exige que você escreva apenas o que você precisa para fazer o trabalho.

Jared
fonte
4

É incrível ver o velho mito "C / C ++ deve ser mais rápido que Java porque Java é interpretado" ainda está vivo e chutando. Há artigos que remontam alguns anos , bem como artigos mais recentes , que explicam com conceitos ou medidas por que isso nem sempre é o caso .

As implementações atuais de máquinas virtuais (e não apenas a JVM, por sinal) podem tirar proveito das informações coletadas durante a execução do programa para ajustar dinamicamente o código enquanto ele é executado, usando uma variedade de técnicas:

  • renderizando métodos frequentes para código de máquina,
  • com pequenos métodos,
  • ajuste de travamento

e vários outros ajustes com base no conhecimento do que o código está realmente fazendo e nas características reais do ambiente em que está sendo executado.

joel.neely
fonte
Concordo que o Java fez melhorias significativas de desempenho nos últimos anos que o aproximam muito de C em termos de desempenho bruto, mas levará um tempo para minimizar o fato de que ficou tão lento por tanto tempo. Mas quem estava falando sobre Java, afinal?
Robert Gamble
Java é uma "outra linguagem" referenciada pelo OP, não é?
317 Robert C. Barth
@ Robert: "outras línguas", plural, nenhuma menção a nenhuma linguagem específica além de C. Como você lê "Java" a partir disso?
Robert Gamble
Robob @: Várias das respostas que foram postadas antes que eu encontrei a pergunta estavam falando de Java (ou outras línguas cuja implementação é muitas vezes via intérprete ou VM).
joel.neely
3
@Joel - Se você conhece o hardware de destino, a maioria das otimizações que a JVM pode fazer em tempo de execução também pode ser feita usando a otimização guiada por perfil com C ou C ++. Isso faz uma enorme diferença e geralmente empurra C e C ++ de volta à liderança, pois eles não precisam "aprender" durante a execução.
Tom
4

O código mais rápido seria o código da máquina cuidadosamente criado à mão. Assembler será quase tão bom. Ambos são de nível muito baixo e é preciso muito código para escrever. C está um pouco acima do assembler. Você ainda tem a capacidade de controlar as coisas em um nível muito baixo na máquina real, mas há abstração suficiente para torná-la mais rápida e fácil do que a montadora. Outros idiomas, como C # e JAVA, são ainda mais abstratos. Enquanto Assembler e código de máquina são chamados de linguagens de baixo nível, C # e JAVA (e muitos outros) são chamados de linguagens de alto nível. C às vezes é chamado de linguagem de nível médio.

Jim C
fonte
Enquanto lia sua resposta, apenas duas palavras no parágrafo inteiro estavam puxando meus olhos em direção a elas, como um ímã puxando metais. A palavra é JAVA, duas vezes no parágrafo. Nunca o vi antes escrito em maiúsculas e está bonito :-)
Sнаношƒаӽ
3

Não tome a palavra de alguém, observe a desmontagem para C e seu idioma de escolha em qualquer parte crítica de desempenho do seu código. Eu acho que você pode simplesmente olhar na janela de desmontagem em tempo de execução no Visual Studio para ver desmontado .Net. Deveria ser possível se complicado para Java usando windbg, embora, se você fizer isso com .Net, muitos dos problemas sejam os mesmos.

Não gosto de escrever em C se não for necessário, mas acho que muitas das afirmações feitas nessas respostas que defendem a velocidade de idiomas diferentes de C podem ser deixadas de lado simplesmente desmontando a mesma rotina em C e no idioma de sua escolha de nível superior, especialmente se houver muitos dados envolvidos, como é comum em aplicativos críticos de desempenho. Fortran pode ser uma exceção em sua área de especialização, não sei. É mais alto que C?

Na primeira vez em que comparei o código JITed com o código nativo, resolvi toda e qualquer dúvida sobre se o código .Net podia ser executado comparativamente ao código C. O nível extra de abstração e todas as verificações de segurança têm um custo significativo. Os mesmos custos provavelmente se aplicariam ao Java, mas não aceite minha palavra, tente algo em que o desempenho seja crítico. (Alguém sabe o suficiente sobre o JITed Java para localizar um procedimento compilado na memória? Certamente deve ser possível)


fonte
2

1) Como outros já disseram, C faz menos por você. Sem variáveis ​​de inicialização, sem verificação de limites de matriz, sem gerenciamento de memória, etc. Esses recursos em outros idiomas custam ciclos de memória e CPU que C não gasta.

2) Respostas dizendo que C é menos abstrato e, portanto, mais rápido, são apenas metade corretas, eu acho. Tecnicamente falando, se você tivesse um "compilador suficientemente avançado" para o idioma X, o idioma X poderia se aproximar ou igual à velocidade de C. A diferença com C é que, uma vez que ele mapeia tão obviamente (se você fez um curso de arquitetura) e diretamente à linguagem assembly que mesmo um compilador ingênuo pode fazer um trabalho decente. Para algo como Python, você precisa de um compilador muito avançado para prever os tipos prováveis ​​de objetos e gerar código de máquina rapidamente - a semântica de C é simples o suficiente para que um compilador simples possa se sair bem.

Joseph Garvin
fonte
2

Nos velhos tempos, havia apenas dois tipos de idiomas: compilados e interpretados.

As linguagens compiladas utilizaram um "compilador" para ler a sintaxe da linguagem e convertê-la em código de linguagem de montagem idêntico, o que poderia ser apenas diretamente na CPU. As linguagens interpretadas usavam alguns esquemas diferentes, mas essencialmente a sintaxe da linguagem foi convertida em uma forma intermediária e, em seguida, executada em um "intérprete", um ambiente para a execução do código.

Assim, de certa forma, havia outra "camada" - o intérprete - entre o código e a máquina. E, como sempre acontece em um computador, mais significa que mais recursos são usados. Os intérpretes eram mais lentos, porque precisavam realizar mais operações.

Mais recentemente, vimos mais linguagens híbridas como Java, que empregam um compilador e um intérprete para fazê-las funcionar. É complicado, mas uma JVM é mais rápida, mais sofisticada e muito mais otimizada do que os antigos intérpretes; portanto, há uma mudança muito melhor de desempenho (ao longo do tempo) mais próximo do código compilado direto. Obviamente, os compiladores mais recentes também têm truques de otimização mais sofisticados, de modo que tendem a gerar código muito melhor do que costumavam. Mas a maioria das otimizações, na maioria das vezes (embora nem sempre), faz algum tipo de troca, de modo que elas nem sempre são mais rápidas em todas as circunstâncias. Como todo o resto, nada é de graça, então os otimizadores devem se gabar de algum lugar (embora muitas vezes o usem em tempo de compilação para economizar tempo de execução da CPU).

Voltando ao C, é uma linguagem simples, que pode ser compilada em um conjunto bastante otimizado e executada diretamente na máquina de destino. Em C, se você incrementa um número inteiro, é mais do que provável que seja apenas uma etapa do assembler na CPU; em Java, no entanto, pode acabar sendo muito mais do que isso (e também pode incluir um pouco de coleta de lixo: -) C oferece uma abstração muito mais próxima da máquina (o montador é o mais próximo), mas você acaba tendo que fazer muito mais trabalho para fazê-lo funcionar e não é tão protegido, fácil de usar ou amigável. A maioria dos outros idiomas oferece uma abstração mais alta e cuida de mais detalhes subjacentes, mas em troca de sua funcionalidade avançada, eles exigem mais recursos para serem executados. Ao generalizar algumas soluções, você precisa lidar com uma ampla variedade de computadores,

Paulo.

Paul W Homer
fonte
"Em C, se você incrementa um número inteiro, é mais do que provável que seja apenas uma etapa do montador na CPU" Não é exatamente verdade. Se esse número inteiro não estiver no registro da CPU, será necessário ter o código da máquina para buscá-lo na memória, incrementá-lo e gravá-lo novamente na memória. Sobre o mesmo que seria de esperar ao executar o código Java. E não entendo por que "++ i" desencadearia por si só um ciclo de GC.
quant_dev 22/06/2009
@quant_dev: "você .. tem ... para buscar na memória, incrementar, escrever de volta ...". Talvez talvez não. O x86, por exemplo, possui instruções que operam com dados na memória. ++ipode ser compilado para "adicionar [ebp - 8], 1". Para não dizer que busca, incremento, armazenamento ainda não está acontecendo, mas isso é resolvido pela CPU e é apenas uma instrução, como Paul disse.
P papai
... que ainda é irrelevante do ponto de vista do desempenho, porque pode ser apenas uma instrução, mas ainda envolve aguardar a chegada dos dados na CPU. Erros de cache e tudo isso.
22286 quant_dev
Não, eu não diria que é irrelevante. Uma instrução de CPU geralmente ocupa menos bytes de código do que várias instruções de CPU, produzindo melhor desempenho de cache no segmento de código. Uma instrução da CPU também ocupa menos espaço no pipeline da CPU, e as várias etapas (busca, incremento, armazenamento) podem ser tratadas - talvez em paralelo - pelos estágios separados do pipeline. De fato, algumas partes de uma operação podem até ser ignoradas se puderem ser combinadas com outras operações no pipeline. Por exemplo, o armazenamento de um valor pode ser combinado com um carregamento subsequente do mesmo valor.
P papai
2

Deixando de lado técnicas avançadas de otimização, como otimização de hot spot , meta-algoritmos pré-compilados e várias formas de paralelismo , a velocidade fundamental de uma linguagem se correlaciona fortemente com a complexidade implícita dos bastidores necessária para dar suporte às operações que normalmente ser especificado dentro de loops internos .

Talvez o mais óbvio seja a verificação de validade em referências indiretas à memória - como a verificação de indicadores nulle a verificação de índices em relação aos limites da matriz. A maioria dos idiomas de alto nível executa essas verificações implicitamente, mas C não. No entanto, isso não é necessariamente uma limitação fundamental dessas outras linguagens - um compilador suficientemente inteligente pode ser capaz de remover essas verificações dos circuitos internos de um algoritmo através de alguma forma de movimento de código invariante em loop .

A vantagem mais fundamental do C (e, de maneira semelhante, o C ++ estreitamente relacionado) é uma forte dependência da alocação de memória baseada em pilha , que é inerentemente rápida para alocação, desalocação e acesso. Em C (e C ++), a pilha de chamadas primária pode ser usada para alocação de primitivos, matrizes e agregados ( struct/ class).

Enquanto C oferece a capacidade de alocar dinamicamente memória de tamanho e vida útil arbitrários (usando o chamado 'heap'), isso é evitado por padrão (a pilha é usada).

Tentadoramente, às vezes é possível replicar a estratégia de alocação de memória C nos ambientes de tempo de execução de outras linguagens de programação. Isso foi demonstrado pelo asm.js , que permite que o código escrito em C ou C ++ seja traduzido em um subconjunto de JavaScript e executado com segurança em um ambiente de navegador da Web - com velocidade quase nativa.


De certa forma, outra área em que C e C ++ ofuscam a maioria das outras linguagens em termos de velocidade é a capacidade de integrar-se perfeitamente aos conjuntos de instruções da máquina nativa. Um exemplo notável disso é a disponibilidade (dependente do compilador e da plataforma) das intrínsecas do SIMD que suportam a construção de algoritmos personalizados que tiram vantagem do hardware de processamento paralelo agora quase onipresente - enquanto ainda utilizam as abstrações de alocação de dados fornecidas pelo idioma (menor alocação de registro de nível de nível é gerenciada pelo compilador).

nobar
fonte
1
Algumas dessas vantagens de alocação de memória do C provavelmente também podem ser replicadas em outros idiomas por compiladores inteligentes (veja aqui ). Tenho a impressão, no entanto, de que isso é estruturalmente muito difícil de fazer - principalmente para tipos de dados não primitivos. Esta publicação menciona a idéia de um objeto não escapante que pode ser alocado por pilha como uma otimização em Java.
dec
2

Eu encontrei uma resposta no link sobre por que algumas linguagens são mais rápidas e outras mais lentas, espero que isso esclareça mais sobre por que C ou C ++ é mais rápido que outros. Existem outras linguagens também que são mais rápidas que C, mas não podemos use todos eles. Alguma explicação -

Uma das grandes razões pelas quais o Fortran permanece importante é porque é rápido: as rotinas de processamento de números escritas no Fortran tendem a ser mais rápidas que as rotinas equivalentes, escritas na maioria dos outros idiomas. As linguagens que estão competindo com o Fortran neste espaço - C e C ++ - são usadas porque são competitivas com esse desempenho.

Isso levanta a questão: por que? O que há no C ++ e no Fortran que os tornam mais rápidos e por que eles superam outras linguagens populares, como Java ou Python?

Interpretação versus compilação Há muitas maneiras de categorizar e definir linguagens de programação, de acordo com o estilo de programação que eles incentivam e os recursos que oferecem. Ao analisar o desempenho, a maior distinção é entre linguagens interpretadas e compiladas.

A divisão não é difícil; pelo contrário, há um espectro. Em uma extremidade, temos as linguagens compiladas tradicionais, um grupo que inclui Fortran, C e C ++. Nesses idiomas, há um estágio de compilação discreto que converte o código fonte de um programa em um formato executável que o processador pode usar.

Esse processo de compilação possui várias etapas. O código fonte é analisado e analisado. Erros básicos de codificação, como erros de digitação e ortografia, podem ser detectados neste momento. O código analisado é usado para gerar uma representação na memória, que também pode ser usada para detectar erros - desta vez, erros semânticos, como chamar funções que não existem ou tentar executar operações aritméticas em sequências de texto.

Essa representação na memória é então usada para acionar um gerador de código, a parte que produz código executável. A otimização do código, para melhorar o desempenho do código gerado, é executada em vários momentos nesse processo: otimizações de alto nível podem ser executadas na representação do código e otimizações de nível inferior são usadas na saída do gerador de código.

A execução do código acontece mais tarde. Todo o processo de compilação é simplesmente usado para criar algo que pode ser executado.

No extremo oposto, temos intérpretes. Os intérpretes incluirão um estágio de análise semelhante ao do compilador, mas isso será usado para direcionar a execução direta, com o programa sendo executado imediatamente.

O intérprete mais simples possui um código executável correspondente aos vários recursos suportados pelo idioma - portanto, ele terá funções para adicionar números, unir strings, qualquer que seja o idioma de um determinado idioma. À medida que analisa o código, ele pesquisa a função correspondente e a executa. As variáveis ​​criadas no programa serão mantidas em algum tipo de tabela de pesquisa que mapeia seus nomes para seus dados.

O exemplo mais extremo do estilo do intérprete é algo como um arquivo em lotes ou um script de shell. Nessas linguagens, o código executável nem sempre é embutido no próprio intérprete, mas em programas independentes separados.

Então, por que isso faz diferença no desempenho? Em geral, cada camada de indireção reduz o desempenho. Por exemplo, a maneira mais rápida de adicionar dois números é ter esses dois números nos registradores no processador e usar as instruções de adição do processador. É o que os programas compilados podem fazer; eles podem colocar variáveis ​​em registradores e tirar proveito das instruções do processador. Mas, em programas interpretados, essa mesma adição pode exigir duas pesquisas em uma tabela de variáveis ​​para buscar os valores a serem adicionados e, em seguida, chamar uma função para executar a adição. Essa função pode muito bem usar a mesma instrução de processador usada pelo programa compilado para executar a adição real, mas todo o trabalho extra antes que a instrução possa realmente ser usada torna as coisas mais lentas.

Se você quiser saber mais, consulte a Fonte

uniqueNt
fonte
1

Alguns algoritmos C ++ são mais rápidos que C e algumas implementações de algoritmos ou padrões de design em outras linguagens podem ser mais rápidas que C.

Quando as pessoas dizem que C é rápido e depois passam a falar sobre outro idioma, geralmente usam o desempenho de C como referência.

Arafangion
fonte
2
"Alguns algoritmos C ++ são mais rápidos que C" não fazem sentido. Qualquer "algoritmo C ++" pode ser escrito em C e vice-versa. Algoritmos são independentes da linguagem. O C ++ basicamente adiciona recursos ao C - e nenhum desses novos recursos leva a algoritmos mais rápidos (embora talvez sejam mais fáceis de escrever).
23410 Joseph Garvin
1
A repreensão clássica é o algoritmo std :: sort .. std :: sort é mais rápido que qualquer algoritmo de classificação em C - a única maneira de obter o mesmo desempenho em C é codificá-lo em qualquer lugar que você quiser ou usar macros - e mesmo assim o compilador possui menos informações para otimizar.
Arafangion
1

Com os compiladores de otimização modernos, é altamente improvável que um programa C puro seja muito mais rápido do que o código .net compilado, se houver. Com o aumento da produtividade que frameworks como .net fornecer o desenvolvedor, você pode fazer coisas em um dia que costumava levar semanas ou meses de C. regulares Juntamente com o custo mais barato de hardware em comparação com o salário de um desenvolvedor, é apenas WAY mais barato para gravação o material em um idioma de alto nível e atire o hardware a qualquer lentidão.

A razão pela qual Jeff e Joel falam sobre C ser a linguagem "real programador" é porque não há manipulação manual em C. Você deve alocar sua própria memória, desalocar essa memória, fazer sua própria verificação de limites etc. Não existe tal coisa como novo objeto (); Não há coleta de lixo, classes, OOP, estruturas de entidade, LINQ, propriedades, atributos, campos ou qualquer coisa assim. Você precisa saber coisas como aritmética do ponteiro e como desreferenciar um ponteiro. E, nesse caso, saiba e entenda o que é um ponteiro. Você precisa saber o que é um quadro de pilha e qual é o ponteiro de instrução. Você precisa conhecer o modelo de memória da arquitetura da CPU em que está trabalhando. Há muita compreensão implícita da arquitetura de um microcomputador (geralmente omicrocomputador em que você está trabalhando) ao programar em C que simplesmente não está presente nem necessário ao programar em algo como C # ou Java. Todas essas informações foram descarregadas para o programador do compilador (ou VM).

Robert C. Barth
fonte
"Jogue mais hardware no problema" só funciona em ambientes onde isso é realmente possível. O mercado incorporado é um contra-exemplo perfeito (e esse é um mercado massivo ).
7269 Bob Somers
Jeff e Joel blogam exclusivamente sobre sistemas de negócios, não sistemas incorporados, portanto, é razoável supor que esse seja o contexto em que essa pergunta foi feita.
22380 Robert C. Barth
1) código .net executando tão rápido quanto o código C? Você já escreveu um programa em C? 2) A mentalidade "jogue mais hardware no problema" é o motivo pelo qual minha máquina de 2 GB e 1,3 GHz e dois núcleos mal consegue acompanhar o Windows XP, enquanto a minha máquina de 800MHz e 512 MB é compatível com a versão mais recente do Ubuntu.
317 Robert Gamble
Sim, eu escrevi C. Não é tão glorioso quanto as pessoas imaginam. E os projetos custam muito. É um caso simples de economia. Corri o Win2k em um Pentium Pro 180MHz com 768MB de RAM por anos como servidor de correio e web. Funcionou muito bem. Evidência anedótica não significa nada.
317 Robert C. Barth
C não é "glorioso", mas é rápido, eu escrevi códigos C e C # suficientes para saber que C quase sempre é muito mais rápido que C # enquanto executa a mesma tarefa. Para algumas tarefas, leva mais tempo para se desenvolver do que em linguagens de nível superior, mas o objetivo é usar a ferramenta certa para o trabalho e, às vezes, C.
7263 Robert Gamble
1

É a diferença entre automático e manual, linguagens de nível superior são abstrações automatizadas. C / C ++ são controlados e manipulados manualmente, mesmo o código de verificação de erros às vezes é um trabalho manual.

C e C ++ também são linguagens compiladas, o que significa que nada disso funciona em todos os lugares, essas linguagens precisam ser ajustadas para o hardware com o qual você trabalha, adicionando uma camada extra de pegadinha. Embora isso esteja um pouco perturbador agora, os compiladores C / C ++ estão se tornando mais comuns em todas as plataformas. Você pode fazer compilações cruzadas entre plataformas. Ainda não é uma situação de execução em todos os lugares, você basicamente instrui o compilador A a compilar no mesmo código a arquitetura diferente do compilador B.

Os idiomas C da linha inferior não devem ser fáceis de entender ou raciocinar; também é por isso que eles são chamados de idiomas de sistemas. Eles surgiram antes de toda essa bobagem de abstração de alto nível. É também por isso que eles não são usados ​​para programação na web de front-end. Eles simplesmente não são adequados para a tarefa, têm o objetivo de resolver problemas complexos que não podem ser resolvidos com ferramentas de linguagem convencionais.

É por isso que você tem coisas malucas como (micro-arquiteturas, drivers, física quântica, jogos AAA, sistemas operacionais), para as quais C e C ++ são adequados. A velocidade e a trituração de números são as principais áreas.

Val
fonte
1

Existem várias razões, incluindo:

  • Compila na linguagem assembly.
  • É digitado estaticamente.
  • Sem coleta de lixo.
  • Sem manipulação de erros.
  • Muitas linguagens de programação adicionam novos recursos. Parte da filosofia do C é manter as coisas simples, em vez de adicionar mais recursos.
Sapphire_Brick
fonte
Por que deveria ser mais rápido porque não é orientado a objetos?
sb27 23/02
A) programação orientada a objeto cria uma necessidade de coleta de lixo, B) grandes recursos como objeto orientado a complexidade de programação add para o compilador,
Sapphire_Brick
A) Não. Consulte C ++ ou Rust. B) Sim, mas também oferece ao Compilador oportunidades para novas otimizações.
sb27 24/02
A) Rust possui coleta de lixo em tempo de compilação, e c ++ possui coleta de lixo para classes, é por isso que possui destruidores ,, B) complexidade otimizada ainda é complexidade
Sapphire_Brick
A) Não é coleta de lixo, o gerenciamento de memória deve ser feito mesmo que você faça seu programa no assembly B) Não. Mais abstração permite que o otimizador faça melhores suposições.
sb27 25/02