Meu entendimento é que o C / C ++ produz código nativo para executar em uma arquitetura de máquina específica. Por outro lado, linguagens como Java e C # são executadas em cima de uma máquina virtual que abstrai a arquitetura nativa. Logicamente, parece impossível para Java ou C # corresponder à velocidade do C ++ devido a esta etapa intermediária, no entanto, me disseram que os compiladores mais recentes ("hot spot") podem atingir essa velocidade ou até excedê-la.
Talvez seja mais uma questão de compilador do que de idioma, mas alguém pode explicar em inglês simples como é possível que um desses idiomas de máquina virtual tenha um desempenho melhor que o idioma nativo?
Respostas:
Geralmente, C # e Java podem ser tão rápidos ou mais rápidos porque o compilador JIT - um compilador que compila sua IL na primeira vez que é executado - pode fazer otimizações que um programa compilado em C ++ não pode porque pode consultar a máquina. Pode determinar se a máquina é Intel ou AMD; Pentium 4, Core Solo ou Core Duo; ou se suporta SSE4, etc.
Um programa C ++ precisa ser compilado previamente, geralmente com otimizações mistas, para que ele decida bem em todas as máquinas, mas não seja otimizado tanto quanto poderia ser para uma única configuração (por exemplo, processador, conjunto de instruções, outro hardware).
Além disso, certos recursos de linguagem permitem que o compilador em C # e Java faça suposições sobre seu código, o que permite otimizar determinadas partes que não são seguras para o compilador C / C ++. Quando você tem acesso aos ponteiros, há muitas otimizações que simplesmente não são seguras.
Além disso, Java e C # podem fazer alocações de heap de maneira mais eficiente que C ++, porque a camada de abstração entre o coletor de lixo e seu código permite que ele faça toda a compactação de heap de uma só vez (uma operação bastante cara).
Agora não posso falar sobre Java neste próximo ponto, mas sei que o C #, por exemplo, removerá métodos e chamadas de métodos quando souber que o corpo do método está vazio. E ele usará esse tipo de lógica em todo o seu código.
Portanto, como você pode ver, existem várias razões pelas quais determinadas implementações em C # ou Java serão mais rápidas.
Agora, tudo isso dito, otimizações específicas podem ser feitas em C ++ que explodirão qualquer coisa que você possa fazer com C #, especialmente na área de gráficos e sempre que estiver perto do hardware. Ponteiros fazem maravilhas aqui.
Então, dependendo do que você está escrevendo, eu iria com um ou outro. Mas se você estiver escrevendo algo que não depende de hardware (driver, videogame etc.), não me preocuparia com o desempenho do C # (novamente não posso falar sobre Java). Vai dar certo.
Do lado do Java, o @Swati aponta um bom artigo:
https://www.ibm.com/developerworks/library/j-jtp09275
fonte
JIT vs. Compilador Estático
Como já foi dito nas postagens anteriores, o JIT pode compilar IL / bytecode no código nativo em tempo de execução. O custo disso foi mencionado, mas não a sua conclusão:
O JIT tem um grande problema: não é possível compilar tudo: a compilação do JIT leva tempo, portanto o JIT compilará apenas algumas partes do código, enquanto um compilador estático produzirá um binário nativo completo: Para alguns tipos de programas, o estático O compilador simplesmente superará facilmente o JIT.
É claro que C # (ou Java ou VB) geralmente é mais rápido para produzir uma solução viável e robusta do que o C ++ (apenas porque o C ++ possui semântica complexa e a biblioteca padrão do C ++, embora interessante e poderosa, é bastante ruim quando comparada à versão completa escopo da biblioteca padrão do .NET ou Java); portanto, normalmente, a diferença entre C ++ e .NET ou Java JIT não será visível para a maioria dos usuários e, para os binários críticos, bem, você ainda pode chamar o processamento C ++ de C # ou Java (mesmo que esse tipo de chamada nativa possa ser bastante caro por si só) ...
Metaprogramação em C ++
Observe que geralmente você está comparando o código de tempo de execução C ++ com seu equivalente em C # ou Java. Mas o C ++ tem um recurso que pode superar o Java / C # imediatamente, que é a metaprogramação de modelos: O processamento do código será feito no tempo de compilação (aumentando assim o tempo de compilação), resultando em zero (ou quase zero) tempo de execução.
Eu ainda tenho um efeito na vida real sobre isso (eu joguei apenas com conceitos, mas até então, a diferença era segundos de execução para JIT e zero para C ++), mas vale a pena mencionar, juntamente com a metaprogramação do modelo de fato não é trivial......
Uso de memória C ++ nativa
O C ++ possui um uso de memória diferente de Java / C # e, portanto, possui vantagens / falhas diferentes.
Independentemente da otimização do JIT, nada será rápido como o acesso direto do ponteiro à memória (vamos ignorar por um momento os caches do processador, etc.). Portanto, se você tiver dados contíguos na memória, acessá-los através de ponteiros C ++ (isto é, ponteiros C ... Vamos dar o devido ao Caesar) passará vezes mais rápido do que em Java / C #. E o C ++ possui RAII, o que facilita muito o processamento do que em C # ou mesmo em Java. C ++ não precisa
using
escopo a existência de seus objetos. E o C ++ não possui umafinally
cláusula. Isso não é um erro.:-)
E, apesar das estruturas primitivas do C #, os objetos C ++ "na pilha" não custarão nada na alocação e destruição e não precisarão de GC para trabalhar em um encadeamento independente para fazer a limpeza.
Quanto à fragmentação da memória, os alocadores de memória em 2008 não são os antigos alocadores de memória de 1980 que geralmente são comparados a uma alocação GC: C ++ não pode ser movida na memória, é verdade, mas, como em um sistema de arquivos Linux: quem precisa de disco rígido desfragmentar quando a fragmentação não acontece? O uso do alocador correto para a tarefa correta deve fazer parte do kit de ferramentas do desenvolvedor C ++. Agora, escrever alocadores não é fácil e, em seguida, a maioria de nós tem coisas melhores para fazer e, na maior parte do tempo, RAII ou GC é mais que suficiente.
Agora, o modelo de memória está se tornando um pouco mais complicado com o aumento da tecnologia multicore e multithreading. Nesse campo, acho que o .NET tem a vantagem, e o Java, disseram-me, manteve o nível superior. É fácil para alguns hackers "simples" elogiarem seu código "próximo à máquina". Mas agora, é muito mais difícil produzir melhor montagem manualmente do que deixar o compilador trabalhar. Para C ++, o compilador geralmente se tornou melhor que o hacker desde uma década. Para C # e Java, isso é ainda mais fácil.
Ainda assim, o novo C ++ 0x padrão imporá um modelo de memória simples aos compiladores C ++, que padronizará (e, portanto, simplificará) o código efetivo de multiprocessamento / paralelo / encadeamento em C ++, e tornará as otimizações mais fáceis e seguras para os compiladores. Mas então, veremos em alguns anos se suas promessas são cumpridas.
C ++ / CLI vs. C # / VB.NET
Nota: Nesta seção, estou falando sobre C ++ / CLI, ou seja, o C ++ hospedado pelo .NET, não o C ++ nativo.
Na semana passada, tive um treinamento sobre otimização do .NET e descobri que o compilador estático é muito importante de qualquer maneira. Tão importante quanto o JIT.
O mesmo código compilado em C ++ / CLI (ou seu ancestral, C ++ gerenciado) pode ser mais rápido que o mesmo código produzido em C # (ou VB.NET, cujo compilador produz a mesma IL que C #).
Como o compilador estático C ++ era muito melhor para produzir código já otimizado do que os C #.
Por exemplo, a função embutida no .NET é limitada a funções cujo código de bytes é menor ou igual a 32 bytes de comprimento. Portanto, algum código em C # produzirá um acessador de 40 bytes, que nunca será incorporado pelo JIT. O mesmo código em C ++ / CLI produzirá um acessador de 20 bytes, que será incorporado pelo JIT.
Outro exemplo são as variáveis temporárias, que são simplesmente compiladas pelo compilador C ++ enquanto ainda são mencionadas na IL produzida pelo compilador C #. A otimização da compilação estática em C ++ resultará em menos código, autorizando uma otimização JIT mais agressiva novamente.
A razão para isso foi especulada como o fato de o compilador C ++ / CLI lucrar com as vastas técnicas de otimização do compilador nativo C ++.
Conclusão
Eu amo C ++.
Mas, na minha opinião, C # ou Java são uma aposta melhor. Não porque eles são mais rápidos que o C ++, mas porque quando você soma suas qualidades, eles acabam sendo mais produtivos, precisando de menos treinamento e tendo bibliotecas padrão mais completas que o C ++. E, como na maioria dos programas, suas diferenças de velocidade (de uma maneira ou de outra) serão desprezíveis ...
Editar (06/06/2011)
Minha experiência em C # / .NET
Eu tenho agora 5 meses de codificação C # profissional quase exclusiva (que adiciona ao meu currículo já cheio de C ++ e Java e um toque de C ++ / CLI).
Eu joguei com WinForms (Ahem ...) e WCF (legal!) E WPF (legal !!!! Tanto por XAML quanto por C # bruto. O WPF é tão fácil que acredito que o Swing simplesmente não se compara a ele) e C # 4.0.
A conclusão é que, embora seja mais fácil / rápido produzir um código que funcione em C # / Java do que em C ++, é muito mais difícil produzir um código forte, seguro e robusto em C # (e ainda mais difícil em Java) do que em C ++. Os motivos não faltam, mas podem ser resumidos por:
using
não são tão fáceis e poderosos porque é difícil escrever implementações corretas do Dispose .readonly
e Javafinal
não são tão úteis quanto os de C ++const
( não há como você expor dados complexos somente de leitura (uma Árvore de Nós, por exemplo) em C # sem um tremendo trabalho, embora seja um recurso interno do C ++. Dados imutáveis são uma solução interessante , mas nem tudo pode ser imutável, portanto, de longe, não é o suficiente ).Portanto, o C # permanece uma linguagem agradável, desde que você queira algo que funcione, mas uma linguagem frustrante no momento em que você deseja algo que sempre e com segurança funcione.
O Java é ainda mais frustrante, pois tem os mesmos problemas que o C # e mais: como não possui a
using
palavra-chave C # , um colega muito experiente gastou muito tempo para garantir que seus recursos fossem liberados corretamente, enquanto o equivalente em C ++ teria foi fácil (usando destruidores e ponteiros inteligentes).Então, acho que o ganho de produtividade do C # / Java é visível para a maioria dos códigos ... até o dia em que você precisar que o código seja o mais perfeito possível. Nesse dia, você conhecerá a dor. (você não vai acreditar no que é solicitado em nossos aplicativos de servidor e GUI ...).
Sobre Java e C ++ do lado do servidor
Eu mantive contato com as equipes de servidores (trabalhei 2 anos entre elas, antes de retornar à equipe da GUI), do outro lado do prédio, e aprendi algo interessante.
Nos últimos anos, a tendência era ter os aplicativos de servidor Java destinados a substituir os aplicativos antigos de servidor C ++, pois o Java possui muitas estruturas / ferramentas e é fácil de manter, implantar etc. etc.
... Até o problema da baixa latência elevar sua cabeça feia nos últimos meses. Então, os aplicativos de servidor Java, independentemente da otimização tentada por nossa equipe qualificada de Java, perderam de forma simples e limpa a corrida contra o antigo servidor C ++ não otimizado.
Atualmente, a decisão é manter os servidores Java para uso comum, onde o desempenho ainda é importante, não está preocupado com o destino de baixa latência e otimizar agressivamente os aplicativos do servidor C ++, que são mais rápidos, para necessidades de baixa latência e ultra-baixa latência.
Conclusão
Nada é tão simples quanto o esperado.
Java e ainda mais C # são linguagens legais, com extensas bibliotecas e estruturas padrão, nas quais você pode codificar rapidamente e ter resultados muito em breve.
Mas quando você precisa de força bruta, otimizações poderosas e sistemáticas, suporte forte ao compilador, recursos poderosos de linguagem e segurança absoluta, Java e C # dificultam a conquista dos últimos percentuais de qualidade ausentes mas críticos, que você precisa manter-se acima da concorrência.
É como se você precisasse de menos tempo e menos desenvolvedores experientes em C # / Java do que em C ++ para produzir código de qualidade média, mas, por outro lado, no momento em que você precisava de um código de qualidade excelente a perfeito, subitamente ficou mais fácil e rápido obter os resultados certo em C ++.
Obviamente, essa é minha própria percepção, talvez limitada a nossas necessidades específicas.
Mas, ainda assim, é o que acontece hoje, tanto nas equipes da GUI quanto nas equipes do lado do servidor.
Obviamente, atualizarei este post se algo novo acontecer.
Editar (22/06/2011)
Fontes:
Editar (20/09/2011)
Fontes:
fonte
Sempre que falo de desempenho gerenciado versus não gerenciado, gosto de apontar para a série Rico (e Raymond) comparando versões C ++ e C # de um dicionário chinês / inglês. Esta pesquisa no Google permitirá que você leia por si mesmo, mas eu gosto do resumo de Rico.
Para mim, a conclusão é que foram necessárias seis revisões para que a versão não gerenciada superasse a versão gerenciada que era uma porta simples do código não gerenciado original. Se você precisar de todo o último desempenho (e tiver tempo e experiência para obtê-lo), terá que ficar sem gerenciamento, mas, para mim, aproveitarei a vantagem da ordem de magnitude que tenho nas primeiras versões dos 33 % Ganho se tentar 6 vezes.
fonte
A compilação para otimizações específicas da CPU geralmente é superestimada. Basta pegar um programa em C ++ e compilar com otimização para pentium PRO e executar em um pentium 4. Em seguida, recompilar com optimize para pentium 4. Passei longas tardes fazendo isso com vários programas. Resultados gerais ?? Geralmente, menos de 2-3% de aumento de desempenho. Portanto, as vantagens teóricas do JIT são quase nenhuma. A maioria das diferenças de desempenho só pode ser observada ao usar os recursos escalares de processamento de dados, algo que eventualmente precisará de ajustes finos manuais para obter o máximo desempenho de qualquer maneira. As otimizações desse tipo são lentas e dispendiosas, o que as torna, às vezes, inadequadas para o JIT.
No mundo real e no aplicativo real, o C ++ ainda é geralmente mais rápido que o java, principalmente devido ao menor espaço de memória que resulta em melhor desempenho do cache.
Mas, para usar todos os recursos do C ++, o desenvolvedor deve trabalhar duro. Você pode obter resultados superiores, mas deve usar seu cérebro para isso. C ++ é uma linguagem que decidiu apresentar a você mais ferramentas, cobrando o preço que você deve aprender para poder usar bem a linguagem.
fonte
O JIT (Compilação Just In Time) pode ser incrivelmente rápido, porque otimiza para a plataforma de destino.
Isso significa que ele pode tirar proveito de qualquer truque do compilador que sua CPU possa suportar, independentemente da CPU em que o desenvolvedor escreveu o código.
O conceito básico do .NET JIT funciona assim (bastante simplificado):
Chamando um método pela primeira vez:
Chamando um método pela segunda vez:
Como você pode ver, na segunda vez, é praticamente o mesmo processo que o C ++, exceto com a vantagem de otimizações em tempo real.
Dito isto, ainda existem outros problemas gerais que diminuem a velocidade de um idioma gerenciado, mas o JIT ajuda muito.
fonte
Eu gosto da resposta de Orion Adrian , mas há outro aspecto nela.
A mesma pergunta foi feita décadas atrás sobre linguagem assembly versus linguagens "humanas" como FORTRAN. E parte da resposta é semelhante.
Sim, um programa C ++ é capaz de ser mais rápido que o C # em qualquer algoritmo (não trivial?), Mas o programa em C # geralmente é tão rápido ou mais rápido que uma implementação "ingênua" em C ++ e uma versão otimizada em C ++ levará mais tempo para se desenvolver e ainda poderá superar a versão C # por uma margem muito pequena. Então, vale mesmo a pena?
Você terá que responder a essa pergunta individualmente.
Dito isso, sou fã de C ++ há muito tempo e acho que é uma linguagem incrivelmente expressiva e poderosa - às vezes subestimada. Mas em muitos problemas da "vida real" (para mim, pessoalmente, isso significa "do tipo que sou pago para resolver"), o C # fará o trabalho mais cedo e com mais segurança.
A maior penalidade que você paga? Muitos programas .NET e Java são porcos de memória. Vi aplicativos .NET e Java ocuparem "centenas" de megabytes de memória, quando programas em C ++ de complexidade semelhante mal arranham as "dezenas" de MBs.
fonte
Não sei com que frequência você descobrirá que o código Java será executado mais rápido que o C ++, mesmo com o Hotspot, mas explicarei como isso pode acontecer.
Pense no código Java compilado como linguagem de máquina interpretada para a JVM. Quando o processador Hotspot percebe que certas partes do código compilado serão usadas várias vezes, ele realiza uma otimização no código da máquina. Como o Assembly de ajuste manual é quase sempre mais rápido que o código compilado em C ++, não há problema em descobrir que o código de máquina ajustado programaticamente não será tão ruim.
Portanto, para código altamente repetitivo, pude ver onde seria possível para a HV Hotspot JVM executar o Java mais rápido que o C ++ ... até que a coleta de lixo entre em jogo. :)
fonte
Since hand-tuning Assembly is almost always faster than C++ compiled code
? O que você quer dizer com "assembly de ajuste manual" e "código compilado em C ++"?Geralmente, o algoritmo do seu programa será muito mais importante para a velocidade do seu aplicativo do que o idioma . Você pode implementar um algoritmo ruim em qualquer idioma, incluindo C ++. Com isso em mente, você geralmente poderá escrever o código das execuções mais rapidamente em uma linguagem que ajuda a implementar um algoritmo mais eficiente.
As linguagens de nível superior se saem muito bem, fornecendo acesso mais fácil a muitas estruturas de dados pré-criadas eficientes e práticas encorajadoras que ajudarão a evitar código ineficiente. É claro que, às vezes, eles também podem facilitar a criação de um monte de códigos muito lentos, assim você ainda precisa conhecer sua plataforma.
Além disso, o C ++ está atualizando os recursos "novos" (observe as aspas), como contêineres STL, ponteiros automáticos etc. - veja a biblioteca de reforço, por exemplo. E você pode ocasionalmente achar que a maneira mais rápida de realizar alguma tarefa requer uma técnica como a aritmética de ponteiros, proibida em uma linguagem de nível superior - embora elas normalmente permitam que você chame uma biblioteca escrita em uma linguagem que possa implementá-la conforme desejado .
O principal é saber o idioma que você está usando, a API associada, o que pode fazer e quais são as limitações.
fonte
Também não sei ... meus programas Java são sempre lentos. :-) Eu nunca notei programas em C # sendo particularmente lentos, no entanto.
fonte
Aqui está outro ponto de referência interessante, que você pode experimentar no seu próprio computador.
Ele compara ASM, VC ++, C #, Silverlight, applet Java, Javascript, Flash (AS3)
Demonstração de velocidade do plugin Roozz
Observe que a velocidade do javascript varia muito, dependendo do navegador que está sendo executado. O mesmo vale para o Flash e o Silverlight, porque esses plug-ins são executados no mesmo processo que o navegador de hospedagem. Mas o plug-in Roozz executa arquivos .exe padrão, que são executados em seu próprio processo, portanto, a velocidade não é influenciada pelo navegador de hospedagem.
fonte
Você deve definir "executar melhor que ..". Bem, eu sei, você perguntou sobre velocidade, mas não é tudo o que conta.
E assim por diante, é tendencioso, sim;)
Com C # e Java, você paga um preço pelo que recebe (codificação mais rápida, gerenciamento automático de memória, grande biblioteca e assim por diante). Mas você não tem muito espaço para discutir sobre os detalhes: pegue o pacote completo ou nada.
Mesmo que esses idiomas possam otimizar algum código para executar mais rápido que o código compilado, toda a abordagem é (IMHO) ineficiente. Imagine dirigir todos os dias 8 km até o local de trabalho, com um caminhão! É confortável, é bom, você está seguro (zona de dobra extrema) e, depois de pisar no acelerador por algum tempo, ele será tão rápido quanto um carro comum! Por que todos nós não temos um caminhão para dirigir para o trabalho? ;)
Em C ++, você obtém o que paga, nem mais, nem menos.
Citando Bjarne Stroustrup: "C ++ é minha linguagem favorita de coleta de lixo porque gera tão pouco lixo" link text
fonte
times
uma concha. Para que ele verifique todo o programa, não apenas um aspecto. Os resultados são semelhantes então?O código executável produzido a partir de um compilador Java ou C # não é interpretado - ele é compilado no código nativo "just in time" (JIT). Portanto, a primeira vez que o código em um programa Java / C # é encontrado durante a execução, há alguma sobrecarga, pois o "compilador de tempo de execução" (também conhecido como compilador JIT) transforma o código de bytes (Java) ou o código IL (C #) em instruções nativas da máquina. No entanto, na próxima vez em que o código for encontrado enquanto o aplicativo ainda estiver em execução, o código nativo será executado imediatamente. Isso explica como alguns programas Java / C # parecem estar lentos inicialmente, mas depois têm um desempenho melhor quanto mais tempo são executados. Um bom exemplo é um site ASP.Net. Na primeira vez em que o site é acessado, pode ser um pouco mais lento, pois o código C # é compilado no código nativo pelo compilador JIT.
fonte
Algumas boas respostas aqui sobre a pergunta específica que você fez. Eu gostaria de dar um passo atrás e olhar para a foto maior.
Lembre-se de que a percepção do usuário sobre a velocidade do software que você escreve é afetada por muitos outros fatores além da otimização do codegen. aqui estão alguns exemplos:
O gerenciamento manual de memória é difícil de executar corretamente (sem vazamentos) e ainda mais difícil de executar com eficiência (libere memória logo após o término). Geralmente, o uso de um GC produz mais um programa que gerencia bem a memória. Você deseja trabalhar muito e atrasar a entrega do seu software, na tentativa de superar o GC?
Meu C # é mais fácil de ler e entender do que meu C ++. Também tenho mais maneiras de me convencer de que meu código C # está funcionando corretamente. Isso significa que eu posso otimizar meus algoritmos com menos risco de introduzir bugs (e os usuários não gostam de software que trava, mesmo que seja rápido!)
Posso criar meu software mais rapidamente em C # do que em C ++. Isso libera tempo para trabalhar no desempenho e ainda entrega meu software no prazo.
É mais fácil escrever uma boa interface do usuário em C # do que em C ++, por isso é mais provável que eu forme o trabalho em segundo plano enquanto a interface do usuário permanecer responsiva ou forneça progresso ou uma interface otimizada quando o programa for bloqueado por um tempo. Isso não torna nada mais rápido, mas deixa os usuários mais felizes com a espera.
Tudo o que eu disse sobre C # provavelmente é verdadeiro para Java, simplesmente não tenho a experiência para dizer com certeza.
fonte
Se você é um programador de Java / C # aprendendo C ++, ficará tentado a pensar em termos de Java / C # e traduzir literalmente a sintaxe C ++. Nesse caso, você obtém apenas os benefícios mencionados anteriormente do código nativo vs. interpretado / JIT. Para obter o maior ganho de desempenho em C ++ vs. Java / C #, você precisa aprender a pensar em C ++ e projetar código especificamente para explorar os pontos fortes do C ++.
Parafraseando Edsger Dijkstra : [sua primeira língua] mutila a mente além da recuperação.
Parafraseando Jeff Atwood : você pode escrever [seu primeiro idioma] em qualquer novo idioma.
fonte
Uma das otimizações de JIT mais significativas é a inclusão de métodos. Java pode até incorporar métodos virtuais, se garantir a correção do tempo de execução. Esse tipo de otimização geralmente não pode ser executado por compiladores estáticos padrão, pois precisa de análise de programa inteiro, o que é difícil por causa da compilação separada (em contraste, o JIT tem todo o programa disponível). A inserção de métodos aprimora outras otimizações, fornecendo blocos de código maiores para otimizar.
A alocação de memória padrão em Java / C # também é mais rápida e a desalocação (GC) não é muito mais lenta, mas apenas menos determinística.
fonte
free
edelete
não são deterministas quer e GC podem ser feitas determinista por não alocar.É improvável que as linguagens de máquina virtual superem as linguagens compiladas, mas podem se aproximar o suficiente para que isso não importe, pelos (pelo menos) pelos seguintes motivos (estou falando de Java aqui, pois nunca fiz C #).
1 / O Java Runtime Environment geralmente é capaz de detectar trechos de código que são executados com freqüência e executar a compilação just-in-time (JIT) dessas seções para que, no futuro, elas sejam executadas na velocidade total compilada.
2 / Vastas partes das bibliotecas Java são compiladas para que, quando você chama uma função de biblioteca, esteja executando código compilado, não interpretado. Você pode ver o código (em C) baixando o OpenJDK.
3 / A menos que você esteja fazendo cálculos maciços, na maioria das vezes seu programa está sendo executado, ele está aguardando a entrada de um ser humano muito lento (relativamente falando).
4 / Como grande parte da validação do bytecode Java é feita no momento do carregamento da classe, a sobrecarga normal das verificações de tempo de execução é bastante reduzida.
5 / Na pior das hipóteses, o código com alto desempenho pode ser extraído para um módulo compilado e chamado do Java (consulte JNI) para que ele seja executado a toda velocidade.
Em resumo, o bytecode Java nunca superará a linguagem de máquina nativa, mas existem maneiras de mitigar isso. A grande vantagem do Java (a meu ver) é a biblioteca padrão ENORME e a natureza de plataforma cruzada.
fonte
Orion Adrian , deixe-me inverter o seu post para ver como seus comentários são infundados, porque muito pode ser dito sobre C ++ também. E dizer que o compilador Java / C # otimiza funções vazias realmente faz você parecer que você não é meu especialista em otimização, porque a) por que um programa real deve conter funções vazias, exceto código legado muito ruim, b) que realmente não é otimização de borda preta e sangrenta.
Além dessa frase, você falou descaradamente sobre ponteiros, mas os objetos em Java e C # basicamente não funcionam como ponteiros em C ++? Eles não podem se sobrepor? Eles não podem ser nulos? C (e a maioria das implementações de C ++) tem a palavra-chave restringir, ambos têm tipos de valor, C ++ tem referência a valor com garantia não nula. O que Java e C # oferecem?
>>>>>>>>>>
Geralmente, C e C ++ podem ser tão rápidos ou mais rápidos porque o compilador AOT - um compilador que compila seu código antes da implantação, de uma vez por todas, na sua memória alta com muitos servidores de compilação principais - pode fazer otimizações que um programa compilado em C # não pode porque tem muito tempo para fazê-lo. O compilador pode determinar se a máquina é Intel ou AMD; Pentium 4, Core Solo ou Core Duo; ou se for compatível com SSE4, etc, e se o seu compilador não suportar o envio em tempo de execução, você poderá resolver isso implementando vários binários especializados.
O programa AC # geralmente é compilado ao executá-lo, para que decida bem em todas as máquinas, mas não é otimizado tanto quanto poderia ser para uma única configuração (por exemplo, processador, conjunto de instruções, outro hardware) e deve levar algum tempo primeiro. Recursos como fissão de loop, inversão de loop, vetorização automática, otimização de todo o programa, expansão de modelo, IPO e muito mais, são muito difíceis de serem resolvidos de maneira completa e completa de uma maneira que não incomode o usuário final.
Além disso, certos recursos de linguagem permitem que o compilador em C ++ ou C faça suposições sobre seu código, o que permite otimizar determinadas partes que não são seguras para o compilador Java / C #. Quando você não tem acesso ao ID completo do tipo de genéricos ou a um fluxo garantido de programa, há muitas otimizações que simplesmente não são seguras.
Além disso, C ++ e C fazem muitas alocações de pilha ao mesmo tempo com apenas um incremento de registro, o que certamente é mais eficiente que as alocações de Javas e C # quanto à camada de abstração entre o coletor de lixo e seu código.
Agora não posso falar sobre Java neste próximo ponto, mas sei que os compiladores C ++, por exemplo, removerão métodos e chamadas de métodos quando souberem que o corpo do método está vazio, eliminará subexpressões comuns e tentarão tentar novamente. para encontrar o uso ideal do registro, ele não impõe a verificação de limites, ele autovectoriza loops e loops internos e inverte de interno para externo, move condicionais para fora dos loops, divide e descomplica loops. Ele expandirá std :: vector em matrizes de sobrecarga zero nativas, como você faria da maneira C. Ele fará otimizações entre procedimentos. Ele construirá valores de retorno diretamente no site do chamador. Dobra e propaga expressões. Reordenará os dados de maneira amigável ao cache. Isso fará a passagem de salto. Ele permite que você escreva rastreadores de raio de tempo de compilação com zero tempo de execução. Isso fará otimizações baseadas em gráficos muito caras. Isso reduzirá a força, caso substitua certos códigos por códigos sintaticamente totalmente desiguais, mas semanticamente equivalentes (o antigo "xor foo, foo" é a otimização mais simples, porém desatualizada). Se você desejar, pode omitir os padrões de ponto flutuante IEEE e habilitar ainda mais otimizações, como reordenar o operando de ponto flutuante. Depois de massagear e massacrar seu código, ele pode repetir todo o processo, porque muitas vezes certas otimizações estabelecem as bases para otimizações ainda mais certas. Também pode tentar novamente com os parâmetros aleatórios e ver como a outra variante obtém pontuação em sua classificação interna. E ele usará esse tipo de lógica em todo o seu código. caso substitua certos códigos por códigos sintaticamente totalmente desiguais, mas semanticamente equivalentes (o antigo "xor foo, foo" é apenas a otimização mais simples, embora desatualizada). Se você desejar, pode omitir os padrões de ponto flutuante IEEE e habilitar ainda mais otimizações, como reordenar o operando de ponto flutuante. Depois de massagear e massacrar seu código, ele pode repetir todo o processo, porque muitas vezes certas otimizações estabelecem as bases para otimizações ainda mais certas. Também pode tentar novamente com os parâmetros aleatórios e ver como a outra variante obtém pontuação em sua classificação interna. E ele usará esse tipo de lógica em todo o seu código. caso substitua certos códigos por códigos sintaticamente totalmente desiguais, mas semanticamente equivalentes (o antigo "xor foo, foo" é apenas a otimização mais simples, embora desatualizada). Se você desejar, pode omitir os padrões de ponto flutuante IEEE e habilitar ainda mais otimizações, como reordenar o operando de ponto flutuante. Depois de massagear e massacrar seu código, ele pode repetir todo o processo, porque muitas vezes certas otimizações estabelecem as bases para otimizações ainda mais certas. Também pode tentar novamente com os parâmetros aleatórios e ver como a outra variante obtém pontuação em sua classificação interna. E ele usará esse tipo de lógica em todo o seu código. Se você desejar, pode omitir os padrões de ponto flutuante IEEE e habilitar ainda mais otimizações, como reordenar o operando de ponto flutuante. Depois de massagear e massacrar seu código, ele pode repetir todo o processo, porque muitas vezes certas otimizações estabelecem as bases para otimizações ainda mais certas. Também pode tentar novamente com os parâmetros aleatórios e ver como a outra variante obtém pontuação em sua classificação interna. E ele usará esse tipo de lógica em todo o seu código. Se você desejar, pode omitir os padrões de ponto flutuante IEEE e habilitar ainda mais otimizações, como reordenar o operando de ponto flutuante. Depois de massagear e massacrar seu código, ele pode repetir todo o processo, porque muitas vezes certas otimizações estabelecem as bases para otimizações ainda mais certas. Também pode tentar novamente com os parâmetros aleatórios e ver como a outra variante obtém pontuação em sua classificação interna. E ele usará esse tipo de lógica em todo o seu código. Também pode tentar novamente com os parâmetros aleatórios e ver como a outra variante obtém pontuação em sua classificação interna. E ele usará esse tipo de lógica em todo o seu código. Também pode tentar novamente com os parâmetros aleatórios e ver como a outra variante obtém pontuação em sua classificação interna. E ele usará esse tipo de lógica em todo o seu código.
Portanto, como você pode ver, existem várias razões pelas quais determinadas implementações em C ++ ou C serão mais rápidas.
Agora, dito isso, muitas otimizações podem ser feitas em C ++ que explodirão tudo o que você poderia fazer com C #, especialmente no domínio de processamento de números, em tempo real e próximo ao metal, mas não exclusivamente lá. Você nem precisa tocar em um ponteiro para percorrer um longo caminho.
Então, dependendo do que você está escrevendo, eu iria com um ou outro. Mas se você estiver escrevendo algo que não depende de hardware (driver, videogame etc.), não me preocuparia com o desempenho do C # (novamente não posso falar sobre Java). Vai dar certo.
<<<<<<<<<<<
Geralmente, certos argumentos generalizados podem parecer interessantes em postagens específicas, mas geralmente não parecem certamente confiáveis.
De qualquer forma, para fazer as pazes: AOT é ótimo, assim como o JIT . A única resposta correta pode ser: Depende. E as pessoas realmente inteligentes sabem que você pode usar o melhor dos dois mundos de qualquer maneira.
fonte
Isso aconteceria apenas se o intérprete Java estiver produzindo um código de máquina que seja realmente melhor otimizado do que o código de máquina que seu compilador está gerando para o código C ++ que você está escrevendo, até o ponto em que o código C ++ é mais lento que o Java e o custo de interpretação.
No entanto, as chances de que isso aconteça são bastante baixas - a menos que talvez o Java tenha uma biblioteca muito bem escrita e você tenha sua própria biblioteca C ++ mal escrita.
fonte
Na verdade, o C # realmente não é executado em uma máquina virtual como o Java. O IL é compilado na linguagem assembly, que é um código totalmente nativo e é executada na mesma velocidade que o código nativo. Você pode pré-JIT um aplicativo .NET que remove completamente o custo do JIT e, em seguida, executa um código totalmente nativo.
A desaceleração com o .NET não ocorrerá porque o código .NET é mais lento, mas porque faz muito mais nos bastidores para fazer coisas como coleta de lixo, verificação de referências, armazenamento de quadros de pilha completos etc. Isso pode ser bastante poderoso e útil quando aplicativos de construção, mas também tem um custo. Observe que você também pode fazer todas essas coisas em um programa C ++ (grande parte da funcionalidade .NET principal é na verdade código .NET que você pode exibir no ROTOR). No entanto, se você escrevesse manualmente a mesma funcionalidade, provavelmente terminaria com um programa muito mais lento, pois o tempo de execução do .NET foi otimizado e ajustado com precisão.
Dito isto, um dos pontos fortes do código gerenciado é que ele pode ser totalmente verificável, ou seja. você pode verificar se o código nunca acessará a memória de outros processos ou fará coisas indesejadas antes de executá-lo. A Microsoft tem um protótipo de pesquisa de um sistema operacional totalmente gerenciado que mostrou surpreendentemente que um ambiente 100% gerenciado pode realmente executar significativamente mais rapidamente do que qualquer sistema operacional moderno, aproveitando essa verificação para desativar os recursos de segurança que não são mais necessários aos programas gerenciados (estamos falando em 10x em alguns casos). A rádio SE tem um ótimo episódio falando sobre esse projeto.
fonte
Em alguns casos, o código gerenciado pode realmente ser mais rápido que o código nativo. Por exemplo, os algoritmos de coleta de lixo "marcar e varrer" permitem que ambientes como o JRE ou CLR liberem um grande número de objetos de vida curta (geralmente) em uma única passagem, onde a maioria dos objetos de heap C / C ++ são liberados um a um. um tempo.
Da wikipedia :
Dito isso, escrevi muito C # e muito C ++, além de executar muitos benchmarks. Na minha experiência, o C ++ é muito mais rápido que o C #, de duas maneiras: (1) se você pegar algum código que você escreveu em C #, portá-lo para C ++, o código nativo tende a ser mais rápido. Quão rápido? Bem, isso varia muito, mas não é incomum ver uma melhoria de velocidade de 100%. (2) Em alguns casos, a coleta de lixo pode desacelerar bastante um aplicativo gerenciado. O .NET CLR faz um trabalho terrível com grandes montantes (por exemplo,> 2 GB) e pode acabar gastando muito tempo no GC - mesmo em aplicativos que possuem poucos ou nenhum objeto de vida útil intermediária.
Obviamente, na maioria dos casos que contei, as linguagens gerenciadas são rápidas o suficiente, e a troca de manutenção e codificação pelo desempenho extra do C ++ simplesmente não é boa.
fonte
Aqui está uma referência interessante http://zi.fi/shootout/
fonte
Na verdade, o HotSpot JVM da Sun usa execução em "modo misto". Ele interpreta o bytecode do método até determinar (geralmente através de um contador de algum tipo) que um determinado bloco de código (método, loop, bloco try-catch, etc.) será executado muito, e então o JIT o compila. O tempo necessário para compilar um método JIT geralmente leva mais tempo do que se o método fosse interpretado se for um método raramente executado. O desempenho geralmente é mais alto para o "modo misto" porque a JVM não perde tempo com o código JIT que raramente é executado, se é que alguma vez é executado. C # e .NET não fazem isso. O .NET JITs tudo o que, muitas vezes, desperdiça tempo.
fonte
Leia sobre o Dynamo do HP Labs , um intérprete para o PA-8000 que roda no PA-8000 e geralmente executa programas mais rapidamente do que o original. Então não vai parecer nada surpreendente!
Não pense nisso como uma "etapa intermediária" - a execução de um programa já envolve muitas outras etapas, em qualquer idioma.
Geralmente se resume a:
os programas têm pontos de acesso, portanto, mesmo se você estiver executando mais lentamente 95% do corpo do código que precisa executar, ainda poderá ser competitivo em termos de desempenho se for mais rápido nos 5% quentes
um HLL sabe mais sobre sua intenção do que um LLL como C / C ++ e, portanto, pode gerar um código mais otimizado (o OCaml tem ainda mais e, na prática, geralmente é ainda mais rápido)
um compilador JIT possui muitas informações que um compilador estático não possui (como os dados reais que você possui neste momento)
um compilador JIT pode fazer otimizações em tempo de execução que os vinculadores tradicionais não têm permissão para fazer (como reordenar ramificações para que o caso comum seja simples ou chamadas de biblioteca embutidas)
Em suma, o C / C ++ é uma linguagem bastante ruim para o desempenho: há relativamente poucas informações sobre seus tipos de dados, nenhuma informação sobre eles e nenhum tempo de execução dinâmico para permitir muita otimização em tempo de execução.
fonte
Você pode obter rajadas curtas quando Java ou CLR é mais rápido que C ++, mas, em geral, o desempenho é pior para a vida útil do aplicativo: consulte www.codeproject.com/KB/dotnet/RuntimePerformance.aspx para obter alguns resultados.
fonte
Aqui está a resposta de Cliff Click: http://www.azulsystems.com/blog/cliff/2009-09-06-java-vs-c-performanceagain
fonte
Isso é ilógico. O uso de uma representação intermediária não prejudica inerentemente o desempenho. Por exemplo, o llvm-gcc compila C e C ++ via LLVM IR (que é uma máquina virtual de registro infinito) para código nativo e alcança excelente desempenho (geralmente superando o GCC).
aqui estão alguns exemplos:
Máquinas virtuais com compilação JIT facilitam a geração de código em tempo de execução (por exemplo,
System.Reflection.Emit
no .NET) para que você possa compilar o código gerado rapidamente em linguagens como C # e F #, mas deve recorrer à gravação de um interpretador comparativamente lento em C ou C ++. Por exemplo, para implementar expressões regulares.Partes da máquina virtual (por exemplo, a barreira de gravação e o alocador) geralmente são escritas no assembler codificado à mão, porque C e C ++ não geram código rápido o suficiente. Se um programa enfatizar essas partes de um sistema, é possível que supere qualquer coisa que possa ser escrita em C ou C ++.
A vinculação dinâmica de código nativo requer conformidade com uma ABI que pode impedir o desempenho e obvia a otimização de todo o programa, enquanto a vinculação é normalmente adiada em VMs e pode se beneficiar de otimizações de todo o programa (como os genéricos reificados do .NET).
Eu também gostaria de resolver alguns problemas com a resposta altamente votada de paercebal acima (porque alguém continua excluindo meus comentários em sua resposta) que apresenta uma visão polarizada contraproducente:
Portanto, a metaprogramação de modelos funciona apenas se o programa estiver disponível em tempo de compilação, o que geralmente não é o caso, por exemplo, é impossível escrever uma biblioteca de expressões regulares com desempenho competitivo em vanilla C ++ porque é incapaz de gerar código de tempo de execução (um aspecto importante do metaprogramação).
Em C #, isso vale apenas para tipos de referência e não para tipos de valor.
As pessoas observaram o Java batendo o C ++ no teste SOR a partir do benchmark SciMark2 precisamente porque os ponteiros impedem otimizações relacionadas a aliases.
Também é importante notar que o .NET digita a especialização de genéricos nas bibliotecas vinculadas dinamicamente após a vinculação, enquanto o C ++ não pode porque os modelos devem ser resolvidos antes da vinculação. E, obviamente, a grande vantagem que os genéricos têm sobre os modelos são as mensagens de erro compreensíveis.
fonte
Além do que outros disseram, do meu entendimento, .NET e Java são melhores na alocação de memória. Por exemplo, eles podem compactar a memória à medida que ela é fragmentada, enquanto o C ++ não pode (nativamente, mas pode se você estiver usando um coletor de lixo inteligente).
fonte
Para qualquer coisa que precise de muita velocidade, a JVM apenas chama uma implementação de C ++, por isso é uma questão mais de quão boas são suas bibliotecas do que quão boa é a JVM para a maioria das coisas relacionadas ao SO. A coleta de lixo reduz sua memória pela metade, mas o uso de alguns dos recursos mais sofisticados de STL e Boost terá o mesmo efeito, mas com muitas vezes o potencial de erro.
Se você estiver apenas usando bibliotecas C ++ e muitos de seus recursos de alto nível em um projeto grande com muitas classes, provavelmente acabará mais devagar do que usando uma JVM. Exceto muito mais propenso a erros.
No entanto, o benefício do C ++ é que ele permite que você se otimize, caso contrário, você fica preso ao que o compilador / jvm faz. Se você criar seus próprios contêineres, escrever seu próprio gerenciamento de memória alinhado, usar o SIMD e soltar para montagem aqui e ali, poderá acelerar pelo menos 2x-4x vezes o que a maioria dos compiladores C ++ fará por conta própria. Para algumas operações, 16x-32x. É usar os mesmos algoritmos; se você usar algoritmos melhores e paralelizar, os aumentos podem ser dramáticos, às vezes milhares de vezes mais rápidos que os métodos comumente usados.
fonte
Eu olho para isso de alguns pontos diferentes.
fonte
Uma resposta muito curta: com um orçamento fixo, você obterá um aplicativo java com melhor desempenho do que um aplicativo C ++ (considerações sobre ROI). Além disso, a plataforma Java possui perfis mais decentes, que ajudarão você a identificar seus pontos de acesso mais rapidamente
fonte