Às vezes, o Java supera o C ++ em benchmarks. Obviamente, às vezes o C ++ supera.
Veja os seguintes links:
- http://keithlea.com/javabench/
- http://blog.dhananjaynene.com/2008/07/performance-comparison-c-java-python-ruby-jython-jruby-groovy/
- http://blog.cfelde.com/2010/06/c-vs-java-performance/
Mas como isso é possível? Surpreende minha mente que o código de código interpretado possa ser mais rápido do que uma linguagem compilada.
Alguém pode me explicar? Obrigado!
java
c++
performance
Deets McGeets
fonte
fonte
Respostas:
Primeiro, a maioria das JVMs inclui um compilador, portanto, "bytecode interpretado" é realmente muito raro (pelo menos no código de referência - não é tão raro na vida real, onde seu código geralmente é mais do que alguns loops triviais que são repetidos com muita frequência )
Segundo, um bom número de benchmarks envolvidos parece ser bastante tendencioso (seja por intenção ou incompetência, não sei dizer). Apenas por exemplo, anos atrás, observei alguns dos códigos-fonte vinculados a partir de um dos links que você postou. Tinha código como este:
Como
calloc
fornece memória que já está zerada, usar ofor
loop para zerá-lo novamente é obviamente inútil. Isso foi seguido (se a memória servir) preenchendo a memória com outros dados de qualquer maneira (e nenhuma dependência de zerar), portanto todo o zeramento era completamente desnecessário. Substituir o código acima por um simplesmalloc
(como qualquer pessoa sã teria usado no início) melhorou a velocidade da versão C ++ o suficiente para vencer a versão Java (por uma margem bastante ampla, se a memória servir).Considere (por outro exemplo) a
methcall
referência usada na entrada do blog em seu último link. Apesar do nome (e como as coisas podem parecer), a versão C ++ disso não está realmente medindo muito a sobrecarga de chamada de método. A parte do código que acaba sendo crítica está na classe Toggle:A parte crítica acaba por ser a
state = !state;
. Considere o que acontece quando alteramos o código para codificar o estado como um emint
vez debool
:Essa pequena alteração melhora a velocidade geral em uma margem de 5: 1 . Embora o benchmark visasse medir o tempo de chamada do método, na realidade, o que estava medindo era o tempo de conversão entre
int
ebool
. Eu certamente concordaria que a ineficiência mostrada pelo original é lamentável - mas, dado o quão raramente parece surgir no código real, e a facilidade com que ele pode ser corrigido quando / se surgir, tenho dificuldade em pensar. disso significa muito.Caso alguém decida executar novamente os benchmarks envolvidos, devo acrescentar que há uma modificação quase igualmente trivial na versão Java que produz (ou pelo menos uma vez produzida - eu não reexecutei os testes com um JVM recente para confirmar que ainda fazem) uma melhoria bastante substancial na versão Java também. A versão Java possui um NthToggle :: Activ () que se parece com isso:
Alterar isso para chamar a função base, em vez de manipular
this.state
diretamente, oferece uma melhoria substancial na velocidade (embora não seja suficiente para acompanhar a versão C ++ modificada).Então, acabamos com uma suposição falsa sobre códigos de bytes interpretados versus alguns dos piores benchmarks (já) que eu já vi. Nem está dando um resultado significativo.
Minha própria experiência é que, com programadores igualmente experientes prestando a mesma atenção à otimização, o C ++ vence o Java com mais frequência - mas (pelo menos entre esses dois), a linguagem raramente faz tanta diferença quanto os programadores e o design. Os benchmarks citados nos dizem mais sobre a (in) competência / (des) honestidade de seus autores do que sobre os idiomas que pretendem ser benchmark.
[Edit: Como está implícito em um lugar acima, mas nunca foi tão diretamente quanto eu provavelmente deveria), os resultados que eu estou citando são os que obtive quando testei isso ~ 5 anos atrás, usando implementações C ++ e Java atuais na época . Não executei novamente os testes com as implementações atuais. Uma olhada, no entanto, indica que o código não foi corrigido; portanto, tudo o que teria mudado seria a capacidade do compilador de encobrir os problemas no código.]
Se ignorarmos os exemplos de Java, no entanto, é realmente possível que o código interpretado seja executado mais rápido que o código compilado (embora difícil e um tanto incomum).
A maneira usual de isso acontecer é que o código que está sendo interpretado é muito mais compacto que o código da máquina ou está sendo executado em uma CPU que possui um cache de dados maior que o cache de código.
Nesse caso, um pequeno intérprete (por exemplo, o intérprete interno de uma quarta implementação) pode caber inteiramente no cache de código, e o programa que está interpretando se encaixa inteiramente no cache de dados. O cache normalmente é mais rápido que a memória principal por um fator de pelo menos 10 e geralmente muito mais (um fator de 100 não é mais particularmente raro).
Portanto, se o cache for mais rápido que a memória principal por um fator N e forem necessárias menos de N instruções de código de máquina para implementar cada código de byte, o código de byte deverá vencer (estou simplificando, mas acho que a ideia geral ainda deve ser aparente).
fonte
O C / C ++ feito à mão por um especialista com tempo ilimitado será pelo menos tão rápido ou mais rápido que o Java. Por fim, o próprio Java é escrito em C / C ++, para que você possa fazer tudo o que o Java faz, se estiver disposto a colocar esforços de engenharia suficientes.
Na prática, no entanto, o Java geralmente é executado muito rápido pelos seguintes motivos:
Ao mesmo tempo, o C / C ++ também possui algumas vantagens:
No geral:
fonte
O tempo de execução Java não está interpretando o bytecode. Em vez disso, ele usa o que é chamado de compilação Just In Time . Basicamente, à medida que o programa é executado, ele pega o bytecode e o converte em código nativo otimizado para a CPU específica.
fonte
Todas as coisas são iguais, você poderia dizer: não, o Java nunca deve ser mais rápido . Você sempre pode implementar Java em C ++ a partir do zero e, assim, obter pelo menos o mesmo desempenho. Na prática, no entanto:
Como um aparte, isso me lembra o debate sobre C nas décadas de 80 e 90. Todo mundo estava pensando "C pode ser tão rápido quanto a montagem?". Basicamente, a resposta foi: não no papel, mas, na realidade, o compilador C criou um código mais eficiente que 90% dos programadores de montagem (bem, depois que amadureceu um pouco).
fonte
http://www.ibm.com/developerworks/java/library/j-jtp09275/index.html
fonte
Enquanto um programa Java completamente otimizado raramente supera um programa C ++ completamente otimizado, diferenças em coisas como gerenciamento de memória podem fazer com que muitos algoritmos sejam implementados idiomaicamente em Java mais rapidamente do que os mesmos algoritmos linguisticamente implementados em C ++.
Como @Jerry Coffin apontou, há muitos casos em que mudanças simples podem tornar o código muito mais rápido - mas muitas vezes é necessário muitos ajustes impuros em um idioma ou outro para que a melhoria de desempenho valha a pena. Isso é provavelmente o que você veria em uma boa referência que mostra o Java se saindo melhor que o C ++.
Além disso, embora geralmente não seja tão significativo, há alguma otimização de desempenho que uma linguagem JIT como Java pode fazer que C ++ não pode. O tempo de execução Java pode incluir aprimoramentos após a compilação do código, o que significa que o JIT pode potencialmente produzir código otimizado para tirar proveito dos novos (ou pelo menos diferentes) recursos da CPU. Por esse motivo, um binário Java de 10 anos pode potencialmente superar um binário C ++ de 10 anos.
Por fim, a segurança completa do tipo no quadro geral pode, em casos muito raros, oferecer melhorias extremas no desempenho. A singularidade , um sistema operacional experimental escrito quase inteiramente em uma linguagem baseada em C #, tem comunicação entre processos e multitarefa muito mais rápida devido ao fato de que não há necessidade de limites de processo de hardware ou alternâncias de contexto caras.
fonte
Postado por Tim Holloway no JavaRanch:
Fonte: http://www.coderanch.com/t/547458/Performance/java/Ahead-Time-vs-Just-time
fonte
Isso ocorre porque a etapa final da geração do código da máquina ocorre de forma transparente dentro da JVM ao executar seu programa Java, em vez de explícita ao criar seu proram C ++.
Você deve considerar o fato de que as JVM modernas gastam bastante tempo compilando o código de bytes em tempo real para o código de máquina nativo para torná-lo o mais rápido possível. Isso permite que a JVM execute todos os tipos de truques do compilador que podem ser ainda melhores sabendo os dados de criação de perfil do programa que está sendo executado.
Tal como incluir automaticamente um getter, para que um JUMP-RETURN não seja necessário apenas para obter um valor, acelera as coisas.
No entanto, o que realmente permitiu programas rápidos é melhor limpar depois. O mecanismo de coleta de lixo em Java é mais rápido que o manual sem malloc em C. Muitas implementações modernas sem malloc usam um coletor de lixo por baixo.
fonte
Resposta curta - não é. Esqueça, o tópico é tão antigo quanto fogo ou roda. Java ou .NET não é e não será mais rápido que C / C ++. É rápido o suficiente para a maioria das tarefas em que você não precisa pensar em otimização. Como formulários e processamento SQL, mas é aí que termina.
Para benchmarks ou aplicativos pequenos escritos por desenvolvedores incompetentes, sim, o resultado final será que o Java / .NET provavelmente estará próximo e talvez até mais rápido.
Na realidade, coisas simples como alocar memória na pilha ou simplesmente usar memzones simplesmente matam o Java / .NET no local.
O mundo da coleta de lixo está usando uma espécie de memzone com toda a contabilidade. Adicione memzone a C e C será mais rápido no local. Especialmente para os benchmarks Java vs. C "código de alto desempenho", que são assim:
Tente usar variáveis baseadas em pilha em C / C ++ (ou posicionamento novo), elas se traduzem em
sub esp, 0xff
, é uma única instrução x86, superada com Java - você não pode ...Na maioria das vezes, vejo aqueles bancos em que o Java contra C ++ são comparados, e isso me leva a pensar, como? Estratégias de alocação de memória incorretas, contêineres auto-crescentes sem reservas, vários novos. Isso nem chega perto do código C / C ++ orientado para o desempenho.
Também é uma boa leitura: https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf
fonte
A realidade é que eles são apenas montadores de alto nível que fazem exatamente o que o programador manda, exatamente como o programador manda na ordem exata que o programador manda. As diferenças de desempenho são tão pequenas que são irrelevantes para todos os fins práticos.
A linguagem não é "lenta", o programador escreveu um programa lento. Muito raramente, um programa escrito da melhor maneira em um idioma supera (para qualquer propósito prático) um programa que faz a mesma coisa usando o melhor caminho da linguagem alternativa, a menos que o autor do estudo queira desbastar seu machado em particular.
Obviamente, se você estiver enfrentando um caso raro, como sistemas embarcados em tempo real, a escolha do idioma pode fazer a diferença, mas com que frequência é esse o caso? e, nesses casos, com que frequência a escolha correta não é cegamente óbvia.
fonte
Keith Lea diz que existem "falhas óbvias", mas não faz nada sobre essas "falhas óbvias". Em 2005, essas tarefas antigas foram descartadas e substituídas pelas tarefas agora mostradas no jogo de benchmarks .
Keith Lea diz que ele "pegou o código de referência para C ++ e Java no agora desatualizado Great Computer Language Shootout e executou os testes", mas na verdade ele só mostra medidas para 14 dos 25 desses testes desatualizados .
Keith Lea agora diz que ele não estava tentando provar nada com o post do blog sete anos antes, mas na época ele disse "Eu estava cansado de ouvir as pessoas dizerem que o Java era lento, quando eu sei que é muito rápido ...", o que sugere Naquela época, havia algo que ele estava tentando provar.
Christian Felde diz a você "Eu não criei o código, apenas refiz os testes". como se isso o absolvesse de qualquer responsabilidade por sua decisão de divulgar medidas das tarefas e programas selecionados por Keith Lea.
As medições de até 25 programas minúsculos fornecem evidências definitivas?
Essas medidas são para programas executados como "modo misto" Java não interpretado Java - "Lembre-se de como o HotSpot funciona". Você pode descobrir facilmente quão bem o Java executa o "bytecode interpretado", porque você pode forçar o Java a interpretar apenas o bytecode - basta cronometrar alguns programas Java executados com e sem a opção -Xint.
fonte
Me diverte o quão difundida é essa noção estranha de "bytecode interpretado". Você já ouviu falar da compilação JIT? Seu argumento não pode ser aplicado ao Java.
Porém, deixando a JVM de lado, há casos em que um código encadeado direto ou mesmo uma interpretação trivial de bytecode podem facilmente superar um código nativo altamente otimizado. A explicação é bem simples: o bytecode pode ser bastante compacto e caberá no seu cache minúsculo quando uma versão de código nativo do mesmo algoritmo acabar com várias falhas de cache para uma única iteração.
fonte
JIT, GC e assim por diante, o C ++ pode ser muito, muito facilmente tornado muito mais lento que o Java. Isso não aparecerá nos benchmarks, mas o mesmo aplicativo criado pelo desenvolvedor Java e um desenvolvedor C ++ pode ser muito mais rápido em Java.
Quanto aos padrões avançados de herança, eles são bem parecidos - o C ++ possui alguns que o Java não possui e vice-versa, mas todos também apresentam uma sobrecarga significativa e significativa. Portanto, nenhuma vantagem especial do C ++ na programação pesada de objetos.
Mais uma ressalva: o GC pode ser mais rápido ou mais lento do que gerenciar alocações manualmente. Se você alocar muitos objetos pequenos, no ambiente do GC geralmente um alocado de memória é alocado e partes dele são despachadas conforme necessário para novos objetos. Em gerenciado - cada objeto = alocação separada leva um tempo significativo. OTOH, se você alocar muita memória de uma só vez e depois atribuir partes dela aos seus objetos manualmente ou usar poucas instâncias maiores de objetos, poderá aparecer muito mais rápido.
fonte
obj.fetchFromDatabase("key")
três vezes em cinco linhas de código para a mesma chave, você pensará duas vezes se deve buscar esse valor uma vez e armazená-lo em cache em uma variável local. Se você escreverobj->"key"
com->
que está sendo sobrecarregado para atuar como banco de dados de busca, você está muito mais propenso a apenas deixá-lo passar, porque o custo da operação não é aparente.De alguma forma, o Stack Exchange não aceita meus outros pontos de pilha, então ... infelizmente nenhuma resposta ...
No entanto, a segunda resposta mais votada aqui está cheia de informações erradas na minha humilde opinião.
Um aplicativo feito à mão por um especialista em C / C ++ SEMPRE será muito mais rápido que um aplicativo Java, ponto final. Não existe 'tão rápido quanto Java ou mais rápido'. é mais rápido, precisamente por causa dos itens que você cita abaixo:
Compilação JIT : Você realmente espera que um otimizador automático tenha a inteligência de um programador especialista e veja o link entre a intenção e o código que a CPU realmente vai executar ??? Além disso, todo o JIT que você faz é tempo perdido em comparação com um programa já compilado.
A Coleta de Lixo é uma ferramenta que simplesmente desaloca recursos que um programador teria esquecido de desalocar, de maneira mais ou menos eficiente.
Evidentemente, isso só pode ser mais lento do que um programador C especialista (você escolheu o termo) faria para lidar com sua memória (e não há vazamentos em aplicativos escritos corretamente).
Um aplicativo C otimizado para desempenho sabe que a CPU está sendo executada, foi compilada, senão isso significa que você não executou todas as etapas de desempenho, não é?
Estatísticas de tempo de execução Isso está além do meu conhecimento, mas suspeito que um especialista em C tenha conhecimento de previsão de ramificação mais do que suficiente para ser mais esperto do que a otimização automatizada -
Bibliotecas muito boas Existem muitas funções não muito otimizadas prontamente disponíveis através de bibliotecas em Java, e o mesmo ocorre em qualquer linguagem, no entanto, as bibliotecas mais otimizadas são escritas em C, especialmente para cálculo.
A JVM é uma camada de abstração, que implica as duas coisas boas, muitas das quais estão acima, e também implica que a solução geral é mais lenta por design.
No geral:
O Java nunca pode atingir a velocidade do C / C ++ devido à maneira como ele trabalha em uma JVM com muita proteção, recursos e ferramentas.
O C ++ tem uma vantagem clara em software otimizado, seja para computação ou jogos, e é comum ver implementações em C ++ ganharem concursos de codificação a tal ponto que as melhores implementações em Java só podem ser vistas na segunda página.
Na prática, o C ++ não é um brinquedo e não permitirá que você se engane com muitos erros que a maioria das linguagens modernas pode suportar, no entanto, por ser mais simples e menos seguro, é inerentemente mais rápido.
E, como conclusão, gostaria de dizer que a maioria das pessoas não dá a mínima para isso, que no final a otimização é um esporte reservado apenas a muito poucos desenvolvedores sortudos e que, exceto nos casos em que o desempenho é realmente uma preocupação (ou seja, onde a multiplicação de hardware por 10 não o ajudará - ou representará alguns milhões, pelo menos), a maioria dos gerentes prefere um aplicativo não otimizado e uma tonelada de hardware.
fonte
new
oumalloc()
. Em geral, pode ser muito mais rápido do que qualquer gerenciamento manual de memória - já que você não seria capaz de realocar objetos manualmente. Portanto, todo o seu raciocínio está claramente errado e tendencioso. Seu conhecimento dos algoritmos de GC e dos métodos de otimização de JIT é muito limitado.Eu já vi pelo menos duas mmo impressionantes feitas em Java, para dizer que não é rápido o suficiente para jogos, é um nome impróprio. Só porque os designers de jogos preferem mais o C ++ do que outras linguagens, diz que não se trata apenas de Java, significa que os programadores nunca se interessaram por outras linguagens / paradigmas de programação. Qualquer coisa em qualquer linguagem tão avançada quanto C / C ++ ou mesmo Java pode produzir código que tecnicamente possa atender ou anular o argumento da velocidade. Tudo bem e dito se resume ao que os programadores sabem, com quais equipes as equipes trabalham mais e mais importante porque usam as ferramentas mencionadas. Como estamos abordando o aspecto de desenvolvimento de jogos da programação, deve haver mais no argumento. Basta colocar ' tudo sobre dinheiro e tempo para um negócio morto, que utiliza ferramentas que atendem ao controle de qualidade e, no mundo real, não pesa nos motivos xx para escolher C ++ em Java ou em qualquer outro idioma. É apenas uma decisão de produção em massa. No nível mais básico dos algoritmos de computação, todos com os quais estamos jogando são uns e zeros, o argumento da velocidade é um dos argumentos mais estúpidos já aplicados aos jogos. Se você quer muito ganho de velocidade, abandone completamente as linguagens de programação e trabalhe com o assembly, que é de longe a melhor vantagem.
fonte