for - c# vs c benchmark




Quanto mais rápido é o C++ do que o C#? (18)

É uma questão extremamente vaga sem respostas definitivas reais.

Por exemplo; Eu prefiro jogar jogos 3D que são criados em C ++ que em C #, porque o desempenho é certamente muito melhor. (E eu conheço o XNA, etc., mas não chega perto do real).

Por outro lado, como mencionado anteriormente; você deve desenvolver em uma linguagem que permite fazer o que você deseja rapidamente e, se necessário, otimizar.

Ou agora é o contrário?

Pelo que ouvi, há algumas áreas em que o C # prova ser mais rápido que o C ++, mas nunca tive coragem de testá-lo sozinho.

Pensei que algum de vocês poderia explicar essas diferenças em detalhes ou me indicar o lugar certo para obter informações sobre isso.


A coleta de lixo é a principal razão pela qual o Java # NÃO pode ser usado para sistemas em tempo real.

  1. Quando o GC acontecerá?

  2. Quanto tempo vai demorar?

Isso não é determinístico.


As linguagens .NET podem ser tão rápidas quanto o código C ++, ou até mais rápido, mas o código C ++ terá uma taxa de transferência mais constante, já que o tempo de execução do .NET deve pausar para o GC , mesmo que seja muito inteligente em relação às suas pausas.

Portanto, se você tiver algum código que precise executar consistentemente rapidamente sem qualquer pausa, o .NET introduzirá a latência em algum momento , mesmo se você for muito cuidadoso com o GC de tempo de execução.


C # pode não ser mais rápido, mas torna o YOU ​​/ ME mais rápido. Essa é a medida mais importante para o que eu faço. :)


C / C ++ pode executar muito melhor em programas onde existem grandes matrizes ou looping pesado / iteração sobre matrizes (de qualquer tamanho). Essa é a razão pela qual os gráficos são geralmente muito mais rápidos em C / C ++, porque operações de matriz pesada são a base de quase todas as operações gráficas. O .NET é notoriamente lento em operações de indexação de matriz devido a todas as verificações de segurança, e isso é especialmente verdadeiro para matrizes multidimensionais (e, sim, matrizes C # retangulares são ainda mais lentas que matrizes C # irregulares).

Os bônus de C / C ++ são mais pronunciados se você mantiver os ponteiros diretos e evitar Boost, std::vector e outros contêineres de alto nível, bem como inline cada pequena função possível. Use matrizes da velha escola sempre que possível. Sim, você precisará de mais linhas de código para realizar a mesma coisa que você fez em Java ou C # ao evitar contêineres de alto nível. Se você precisa de uma matriz de tamanhos dinâmicos, você só precisa lembrar de emparelhar seu new T[] com uma instrução delete[] correspondente (ou use std::unique_ptr ) - o preço para a velocidade extra é que você deve codificar com mais cuidado . Mas, em troca, você se livra da sobrecarga de memória gerenciada / coletor de lixo, o que pode facilmente ser 20% ou mais do tempo de execução de programas altamente orientados a objetos em Java e .NET, bem como aqueles gerenciados em massa. custos de indexação do array de memória. Os aplicativos C ++ também podem se beneficiar de alguns comutadores de compilador bacanas em certos casos específicos.

Eu sou um programador especialista em C, C ++, Java e C #. Recentemente tive a rara ocasião de implementar exatamente o mesmo programa algorítmico nos últimos 3 idiomas. O programa teve um monte de operações matriciais matemáticas e multidimensionais. Eu otimizei bastante isso em todos os 3 idiomas. Os resultados foram típicos do que eu normalmente vejo em comparações menos rigorosas: o Java era 1,3x mais rápido que o C # (a maioria das JVMs é mais otimizada que o CLR) e a versão do ponteiro bruta C ++ veio em cerca de 2,1x mais rápido que o C #. Observe que o programa C # usou apenas código seguro - é minha opinião que você pode codificá-lo em C ++ antes de usar a palavra-chave unsafe .

Para que ninguém pense que tenho algo contra o C #, terminarei dizendo que C # é provavelmente minha linguagem favorita. É a linguagem de desenvolvimento mais lógica, intuitiva e rápida que encontrei até agora. Eu faço todo o meu protótipo em c #. A linguagem C # tem muitas vantagens pequenas e sutis em relação ao Java (sim, eu sei que a Microsoft teve a chance de consertar muitos dos problemas do Java ao entrar no jogo com atraso e possivelmente copiar o Java). Toast to Java's Calendar class alguém? Se a Microsoft gastar algum esforço real para otimizar o CLR e o .NET JITter, o C # poderá assumir seriamente o controle. Estou sinceramente surpreso que eles ainda não o tenham feito - eles fizeram muitas coisas na linguagem C #, por que não seguir com otimizações de compiladores de grande impacto? Talvez se todos nós implorarmos.


Como de costume, depende do aplicativo. Há casos em que o C # é provavelmente negligivelmente mais lento e outros casos em que o C ++ é 5 ou 10 vezes mais rápido, especialmente nos casos em que as operações podem ser facilmente SIMD.


Eu sei que não é o que você estava perguntando, mas C # é muitas vezes mais rápido para escrever do que C + +, que é um grande bônus em um ambiente comercial.


Eu testei vector em C ++ e C # equivalente - List e arrays 2D simples.

Estou usando as edições do Visual C # / C ++ 2010 Express. Ambos os projetos são aplicativos de console simples, testei-os em modo de liberação e depuração padrão (sem configurações personalizadas). C # listas correr mais rápido no meu pc, inicialização de matriz também é mais rápida em C #, operações matemáticas são mais lentas.

Estou usando o Intel Core2Duo [email protected], C # - .NET 4.0.

Eu sei que a implementação vetorial é diferente da lista C #, mas eu só queria testar coleções que eu usaria para armazenar meus objetos (e poder usar o acessador de índice).

Claro que você precisa limpar a memória (digamos para cada uso de new ), mas eu queria manter o código simples.

Teste do vetor C ++ :

static void TestVector()
{
    clock_t start,finish;
    start=clock();
    vector<vector<double>> myList=vector<vector<double>>();
    int i=0;
    for( i=0; i<500; i++)
    {
        myList.push_back(vector<double>());
        for(int j=0;j<50000;j++)
            myList[i].push_back(j+i);
    }
    finish=clock();
    cout<<(finish-start)<<endl;
    cout<<(double(finish - start)/CLOCKS_PER_SEC);
}

Teste de lista C #:

private static void TestVector()
{

    DateTime t1 = System.DateTime.Now;
    List<List<double>> myList = new List<List<double>>();
    int i = 0;
    for (i = 0; i < 500; i++)
    {
        myList.Add(new List<double>());
        for (int j = 0; j < 50000; j++)
            myList[i].Add(j *i);
    }
    DateTime t2 = System.DateTime.Now;
    Console.WriteLine(t2 - t1);
}

C ++ - array:

static void TestArray()
{
    cout << "Normal array test:" << endl;
    const int rows = 5000;
    const int columns = 9000;
    clock_t start, finish;

    start = clock();
    double** arr = new double*[rows];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    finish = clock();

    cout << (finish - start) << endl;

    start = clock();
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    finish = clock();

    cout << (finish - start) << endl;
}

Matriz C #:

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i * j;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

}

Horário: (Release / Debug)

C ++

  • Inicialização de 600/606 ms,
  • Preenchimento de matriz de 200/270 ms,
  • 1sec / 13sec vector init & fill.

(Sim, 13 segundos, sempre tenho problemas com listas / vetores no modo de depuração.)

C #:

  • 20/20 ms init,
  • Preenchimento de matriz de 403/440 ms,
  • 710/742 ms lista init e preenchimento.

Nós tivemos que determinar se o C # era comparável ao C ++ no desempenho e eu escrevi alguns programas de teste para isso (usando o Visual Studio 2005 para ambos os idiomas). Descobriu-se que sem a coleta de lixo e considerando apenas a linguagem (não o framework), o C # tem basicamente o mesmo desempenho que o C ++. A alocação de memória é muito mais rápida em C # do que em C ++ e C # tem uma ligeira vantagem no determinismo quando os tamanhos de dados são aumentados além dos limites da linha de cache. No entanto, tudo isso acabou sendo pago e há um custo enorme na forma de resultados de desempenho não determinísticos para C # devido à coleta de lixo.


Na minha experiência (e eu tenho trabalhado muito com ambas as linguagens), o principal problema com o C # comparado ao C ++ é o alto consumo de memória, e eu não encontrei uma boa maneira de controlá-lo. Foi o consumo de memória que acabaria por retardar o software .NET.

Outro fator é que o compilador JIT não pode gastar muito tempo para fazer otimizações avançadas, porque ele é executado em tempo de execução, e o usuário final notaria se demorasse muito tempo. Por outro lado, um compilador C ++ tem todo o tempo necessário para fazer otimizações em tempo de compilação. Este fator é muito menos significativo do que o consumo de memória, IMHO.


Para problemas 'embarassingly parallel', ao usar o Intel TBB e o OpenMP em C ++, observei um aumento de aproximadamente 10x no desempenho em comparação com problemas similares (matemática pura) feitos com C # e TPL. SIMD é uma área onde o C # não pode competir, mas também tenho a impressão de que o TPL tem uma sobrecarga considerável.

Dito isso, eu só uso C ++ para tarefas críticas de desempenho, onde sei que serei capaz de multithread e obter resultados rapidamente. Para todo o resto, C # (e ocasionalmente F #) está bem.


São cinco laranjas mais rápidas. Ou melhor: não pode haver resposta correta (correta). C ++ é uma linguagem estaticamente compilada (mas também há otimização orientada a perfil), C # é executado auxiliado por um compilador JIT. Há tantas diferenças que perguntas como "quanto mais rápido" não podem ser respondidas, nem mesmo dando ordens de magnitude.


Vou começar por discordar de parte da resposta aceita (e bem votada) para esta questão, afirmando:

Na verdade, existem muitas razões pelas quais o código JITted será executado mais lentamente do que um programa C ++ (ou outra linguagem sem sobrecarga de tempo de execução) adequadamente otimizada, incluindo:

  • Os ciclos de computação gastos no código JIT em tempo de execução são, por definição, indisponíveis para uso na execução do programa.

  • qualquer caminho quente no JITter estará competindo com seu código de instrução e cache de dados na CPU. Sabemos que o cache domina quando se trata de desempenho e linguagens nativas como o C ++ não possuem esse tipo de contenção, por definição.

  • o orçamento de tempo de um otimizador de tempo de execução é necessariamente muito mais restrito do que o de um otimizador de tempo de compilação (como outro comentarista apontou)

Conclusão: Em última análise, você quase certamente será capaz de criar uma implementação mais rápida em C ++ do que em C # .

Agora, com isso dito, quanto mais rápido realmente não é quantificável, pois há muitas variáveis: a tarefa, o domínio do problema, o hardware, a qualidade das implementações e muitos outros fatores. Você terá executado testes em seu cenário para determinar a diferença no desempenho e, em seguida, decidir se vale a pena o esforço e a complexidade adicionais.

Este é um tópico muito longo e complexo, mas eu sinto que vale a pena mencionar que o otimizador de tempo de execução do C # é excelente, e é capaz de executar certas otimizações dinâmicas em tempo de execução que simplesmente não estão disponíveis para C ++ com seu tempo de compilação ( estático). Mesmo com isso, a vantagem ainda é tipicamente profunda no campo do aplicativo nativo, mas o otimizador dinâmico é a razão do qualificador " quase certamente" dado acima.

-

Em termos de desempenho relativo, também fiquei perturbado com os números e as discussões que vi em algumas outras respostas, então pensei em falar e, ao mesmo tempo, dar algum apoio às declarações que fiz acima.

Uma grande parte do problema com esses benchmarks é que você não pode escrever código C ++ como se estivesse escrevendo C # e espera obter resultados representativos (por exemplo, executar milhares de alocações de memória em C ++ vai lhe dar números terríveis).

Em vez disso, escrevi um código C ++ um pouco mais idiomático e comparei com o código C # fornecido pelo @Wiory. As duas principais mudanças que fiz no código C ++ foram:

1) usado vector :: reserve ()

2) achatou a matriz 2d para 1d para obter melhor localidade de cache (bloco contíguo)

C # (.NET 4.6.1)

private static void TestArray()
{
    const int rows = 5000;
    const int columns = 9000;
    DateTime t1 = System.DateTime.Now;
    double[][] arr = new double[rows][];
    for (int i = 0; i < rows; i++)
        arr[i] = new double[columns];
    DateTime t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);

    t1 = System.DateTime.Now;
    for (int i = 0; i < rows; i++)
        for (int j = 0; j < columns; j++)
            arr[i][j] = i;
    t2 = System.DateTime.Now;

    Console.WriteLine(t2 - t1);
}

Tempo de execução (Release): Init: 124ms, Fill: 165ms

C ++ 14 (Clang v3.8 / C2)

#include <iostream>
#include <vector>

auto TestSuite::ColMajorArray()
{
    constexpr size_t ROWS = 5000;
    constexpr size_t COLS = 9000;

    auto initStart = std::chrono::steady_clock::now();

    auto arr = std::vector<double>();
    arr.reserve(ROWS * COLS);

    auto initFinish = std::chrono::steady_clock::now();
    auto initTime = std::chrono::duration_cast<std::chrono::microseconds>(initFinish - initStart);

    auto fillStart = std::chrono::steady_clock::now();

    for(auto i = 0, r = 0; r < ROWS; ++r)
    {
        for (auto c = 0; c < COLS; ++c)
        {
            arr[i++] = static_cast<double>(r * c);
        }
    }

    auto fillFinish = std::chrono::steady_clock::now();
    auto fillTime = std::chrono::duration_cast<std::chrono::milliseconds>(fillFinish - fillStart);

    return std::make_pair(initTime, fillTime);
}

Tempo de execução (Release): Init: 398µs (sim, isso é microssegundos), Fill: 152ms

Tempo total de execução: C #: 289ms, C ++ 152ms (aproximadamente 90% mais rápido)

Observações

  • A alteração da implementação do C # para a mesma implementação da matriz 1d resultou em Init: 40ms, Fill: 171ms, Total: 211ms (o C ++ ainda era quase 40% mais rápido ).

  • É muito mais difícil projetar e escrever código "rápido" em C ++ do que escrever código "regular" em qualquer idioma.

  • É (talvez) surpreendentemente fácil obter um desempenho ruim em C ++; vimos isso com desempenho de vetores sem reservas. E há muitas armadilhas como essa.

  • O desempenho do C # é bastante surpreendente quando você considera tudo o que está acontecendo em tempo de execução. E esse desempenho é relativamente fácil de acessar.

  • Mais dados anedóticos comparando o desempenho de C ++ e C #: https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

A conclusão é que o C ++ oferece muito mais controle sobre o desempenho. Você quer usar um ponteiro? Uma referência? Pilha de memória? Heap Polimorfismo dinâmico ou elimina a sobrecarga de tempo de execução de um vtable com polimorfismo estático (via templates / CRTP)? Em C ++ você tem que ... er, fazer todas essas escolhas (e mais), idealmente para que sua solução resolva melhor o problema que você está enfrentando.

Pergunte a si mesmo se você realmente quer ou precisa desse controle, porque mesmo para o exemplo trivial acima, você pode ver que, embora haja uma melhoria significativa no desempenho, isso requer um investimento mais profundo para acessar.


> Afinal, as respostas têm que estar em algum lugar, não têm? :)

Umm não.

Como várias respostas observadas, a questão é sub-especificada de maneiras que convidam perguntas em resposta, não respostas. Para tomar apenas um caminho:

E então quais programas? Qual máquina? Qual sistema operacional? Qual conjunto de dados?


Inspirado por isso, fiz um teste rápido com 60% de instrução comum necessária na maioria dos programas.

Aqui está o código c #:

for (int i=0; i<1000; i++)
{
    StreamReader str = new StreamReader("file.csv");
    StreamWriter stw = new StreamWriter("examp.csv");
    string strL = "";
    while((strL = str.ReadLine()) != null)
    {
        ArrayList al = new ArrayList();
        string[] strline = strL.Split(',');
        al.AddRange(strline);
        foreach(string str1 in strline)
        {
            stw.Write(str1 + ",");
        }
        stw.Write("\n");
    }
    str.Close();
    stw.Close();
}

Matriz de cadeia e arraylist são usados ​​propositadamente para incluir essas instruções.

Aqui está o código c ++:

for (int i = 0; i<1000; i++)
{
    std::fstream file("file.csv", ios::in);
    if (!file.is_open())
    {
        std::cout << "File not found!\n";
        return 1;
    }

    ofstream myfile;
    myfile.open ("example.txt");
    std::string csvLine;

    while (std::getline(file, csvLine))
    {
        std::istringstream csvStream(csvLine);
        std::vector csvColumn;
        std::string csvElement;

        while( std::getline(csvStream, csvElement, ‘,’) )
        {
            csvColumn.push_back(csvElement);
        }

        for (std::vector::iterator j = csvColumn.begin(); j != csvColumn.end(); ++j)
        {
            myfile << *j << ", ";
        }

        csvColumn.clear();
        csvElement.clear();
        csvLine.clear();
        myfile << "\n";
    }
    myfile.close();
    file.close();
}

O tamanho do arquivo de entrada que usei era de 40 KB.

E aqui está o resultado -

  • O código C ++ foi executado em 9 segundos.
  • Código c #: 4 segundos !!!

Ah, mas isso foi no Linux ... Com o C # rodando no Mono ... E o C ++ com o g ++.

OK, isso é o que eu tenho no Windows - Visual Studio 2003 :

  • Código c # correu em 9 segundos.
  • Código C ++ - horrível 370 segundos !!!

Bem, isto depende. Se o byte-code é traduzido em código de máquina (e não apenas JIT) (se você executar o programa) e se seu programa usa muitas alocações / desalocações, pode ser mais rápido porque o algoritmo GC precisa apenas de uma passagem (teoricamente) através de toda a memória uma vez, mas chamadas C / C ++ malloc / realloc / free normais causam uma sobrecarga em todas as chamadas (sobrecarga de chamadas, sobrecarga da estrutura de dados, erros de cache;)).

Então é teoricamente possível (também para outras linguagens GC).

Eu realmente não vejo a extrema desvantagem de não ser capaz de usar a metaprogramming com C # para a maioria dos aplicativos, porque a maioria dos programadores não a usam de qualquer maneira.

Outra grande vantagem é que o SQL, como a "extensão" LINQ , oferece oportunidades para o compilador otimizar chamadas para bancos de dados (em outras palavras, o compilador poderia compilar todo o LINQ para um binário "blob" onde as funções chamadas são embutidas ou para o seu uso otimizado, mas estou especulando aqui).


Eu suponho que existem aplicações escritas em C # rodando rápido, assim como há mais aplicativos escritos em C ++ rodando rápido (bem C ++ apenas mais antigo ... e pegue o UNIX também ...)
- a questão é de fato - o que é essa coisa, usuários e os desenvolvedores estão reclamando sobre ...
Bem, IMHO, no caso de C # temos muito conforto UI, hierarquia muito agradável de bibliotecas e todo o sistema de interface do CLI. No caso de C ++, temos modelos, ATL, COM, MFC e todo o código já escrito e em execução como OpenGL, DirectX e assim por diante ... Desenvolvedores reclamam de chamadas indeterminavelmente aumentadas de GC em caso de C # (significa que o programa é executado rapidamente e em um segundo - bang! está preso).
Escrever código em C # muito simples e rápido (para não esquecer que também aumenta a chance de erros. No caso de C ++, desenvolvedores reclamam de vazamentos de memória, - significa esmagamentos, chamadas entre DLLs, assim como de "DLL hell" - problema com Suporte e substituição de bibliotecas por outras mais recentes ...
Acho que mais habilidade que você terá na linguagem de programação, mais qualidade (e velocidade) irá caracterizar seu software.


Isso realmente depende do que você está tentando realizar no seu código. Ouvi dizer que é apenas uma coisa da lenda urbana que existe alguma diferença de desempenho entre VB.NET, C # e C ++ gerenciado. No entanto, descobri, pelo menos nas comparações de string, que o C ++ gerenciado supera as calças do C #, que, por sua vez, bate as calças do VB.NET.

De forma alguma fiz comparações exaustivas na complexidade algorítmica entre os idiomas. Eu também estou usando apenas as configurações padrão em cada um dos idiomas. Em VB.NET estou usando configurações para exigir declaração de variáveis, etc. Aqui está o código que estou usando para o gerenciado C ++: (Como você pode ver, esse código é bem simples). Estou executando o mesmo em outros idiomas no Visual Studio 2013 com o .NET 4.6.2.

#include "stdafx.h"

using namespace System;
using namespace System::Diagnostics;

bool EqualMe(String^ first, String^ second)
{
    return first->Equals(second);
}
int main(array<String ^> ^args)
{
    Stopwatch^ sw = gcnew Stopwatch();
    sw->Start();
    for (int i = 0; i < 100000; i++)
    {
        EqualMe(L"one", L"two");
    }
    sw->Stop();
    Console::WriteLine(sw->ElapsedTicks);
    return 0;
}




benchmarking