[C#] C ++보다 C ++이 얼마나 빠릅니까?

아니면 지금 다른 방향입니까?

내가 들었던 것에서 C #이 C ++보다 빠르다는 영역이 있지만 직접 테스트 할 용기는 없었습니다.

이러한 차이점을 자세히 설명하거나 이에 대한 정보를 얻을 수있는 적절한 장소를 알려줄 수 있다고 생각했습니다.



답변

JIT가있는 C # 또는 Java와 같은 바이트 코드 기반 언어가 C ++ 코드만큼 빠를 수없는 확실한 이유는 없습니다. 그러나 C ++ 코드는 오랫동안 훨씬 더 빨랐으며 오늘날에도 여전히 많은 경우가 있습니다. 이는 주로 고급 JIT 최적화가 구현하기가 복잡하기 때문이며 실제로 멋진 기능은 지금 막 도착했습니다.

따라서 많은 경우 C ++이 더 빠릅니다. 그러나 이것은 답의 일부일뿐입니다. C ++이 실제로 더 빠른 경우는 고도로 최적화 된 프로그램이며, 전문 프로그래머는 코드에서 지옥을 철저히 최적화합니다. 이 작업은 시간이 많이 걸리고 비용이 많이들뿐만 아니라 지나치게 최적화되어 오류가 발생하기도합니다.

반면, 해석 된 언어의 코드는 아무 것도하지 않고도 이후 버전의 런타임 (.NET CLR 또는 Java VM)에서 더 빨라집니다. 그리고 JIT 컴파일러가 포인터를 사용하는 언어에서는 불가능한 유용한 최적화가 많이 있습니다. 또한 일부는 가비지 수집이 일반적으로 수동 메모리 관리만큼 빠르거나 빠르지 않아야한다고 주장합니다. 일반적으로 C ++ 또는 C에서이 모든 것을 구현하고 달성 할 수 있지만 훨씬 더 복잡하고 오류가 발생하기 쉽습니다.

도널드 크 누스 (Donald Knuth)는“조기 최적화는 모든 악의 근원”이라고 말했다. 응용 프로그램이 주로 성능이 매우 중요한 산술로 구성되고 병목 현상이 발생하고 C ++에서는 더 빨라질 것이라는 것을 확실히 알고 있다면 C ++이 다른 응용 프로그램과 충돌하지 않을 것입니다. 요구 사항은 C ++로 이동하십시오. 다른 경우에는 먼저 가장 적합한 언어로 응용 프로그램을 올바르게 구현하는 데 집중 한 다음 너무 느리게 실행되면 성능 병목 현상을 찾은 다음 코드를 최적화하는 방법에 대해 생각하십시오. 최악의 경우 외부 함수 인터페이스를 통해 C 코드를 호출해야 할 수 있으므로 하위 언어로 중요한 부분을 작성할 수 있습니다.

올바른 프로그램을 최적화하는 것은 상대적으로 쉽지만 최적화 된 프로그램을 수정하는 것이 훨씬 어렵다는 점에 유의하십시오.

속도 이점의 실제 비율을 제공하는 것은 불가능하며 코드에 따라 크게 다릅니다. 대부분의 경우 프로그래밍 언어 구현은 병목 현상이 아닙니다. http : //benchmarksgame.alioth.debian .


답변

C #은 빠르지는 않지만 귀하 / ME를 더 빠르게 만듭니다. 그것이 내가하는 일에 대한 가장 중요한 척도입니다. 🙂


답변

오렌지 5 개가 더 빠릅니다. 또는 오히려 : (올바른) 담요 답변이 없을 수 있습니다. C ++는 정적으로 컴파일 된 언어입니다 (그러나 프로파일 가이드 최적화도 있습니다). C #은 JIT 컴파일러의 도움을받습니다. “얼마나 더 빠른가”와 같은 질문에 대해 질서를내는 것조차도 대답 할 수없는 많은 차이가 있습니다.


답변

나는 다음과 같이 진술함으로써이 질문에 대해 받아 들여지고 잘 찬성 된 답변의 일부에 동의하지 않는 것으로 시작할 것입니다.

실제로 JITted 코드가 올바르게 최적화 된 C ++ (또는 런타임 오버 헤드가없는 다른 언어) 프로그램보다 느리게 실행되는 이유는 다음과 같습니다.

  • 런타임에 JITting 코드에 소비 된 계산주기는 정의상 프로그램 실행에 사용할 수 없습니다.

  • JITter의 모든 핫 경로는 CPU의 명령 및 데이터 캐시 코드와 경쟁합니다. 우리는 캐시가 성능면에서 지배적이며 C ++와 같은 모국어에는 정의에 따라 이러한 유형의 경합이 없습니다.

  • 런타임 최적화 프로그램의 시간 예산은 컴파일 타임 최적화 프로그램의 예산 보다 훨씬 더 제한적입니다 (다른 의견자가 지적했듯이)

결론은 : 궁극적으로, 당신은 할 것이다 거의 확실하게 당신이 C #의 수보다 C ++로 빠른 구현을 만들 수 있습니다 .

이제 말했듯이, 작업, 문제 영역, 하드웨어, 구현 품질 및 기타 많은 요인과 같은 변수가 너무 많기 때문에 실제로 얼마나 빨리 정량화 할 수 없습니까? 시나리오에서 테스트를 실행하여 성능의 차이를 판별 한 후 추가 노력과 복잡성에 대한 가치가 있는지 여부를 결정합니다.

이것은 매우 길고 복잡한 주제이지만 C #의 런타임 최적화 프로그램이 우수하다는 완전성을 위해 언급 할 가치가 있으며 런타임에 C ++에서는 컴파일 타임으로 사용할 수없는 특정 동적 최적화를 수행 할 수 있습니다 ( static) 옵티 마이저. 그럼에도 불구하고, 장점은 여전히 ​​기본 응용 프로그램의 법원에 깊이 있지만, 동적 최적화 프로그램은 위에서 언급 한 ” 거의 확실하게”한정자 의 이유입니다 .

상대적인 성과 측면에서, 나는 다른 답변에서 본 인물과 토론에 혼란을 겪었습니다. 따라서 동시에 차임 할 것이라고 생각했으며 위에서 언급 한 진술에 대한 약간의 지원을 제공했습니다.

이러한 벤치 마크 문제의 큰 부분은 C #을 작성하는 것처럼 C ++ 코드를 작성할 수 없으며 대표 결과를 얻을 수 있다는 것입니다 (예 : C ++에서 수천 개의 메모리 할당을 수행하면 끔찍한 숫자가 나타납니다).

대신 약간 더 관용적 인 C ++ 코드를 작성하고 제공된 @Wiory C # 코드와 비교했습니다. C ++ 코드에서 변경된 두 가지 주요 사항은 다음과 같습니다.

1) 사용 된 vector :: reserve ()

2) 더 나은 캐시 위치를 달성하기 위해 2d 배열을 1d로 평면화했습니다 (연속 블록)

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

런타임 (릴리스) : 초기화 : 124ms, 채우기 : 165ms

C ++ 14 (클랑 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);
}

런타임 (릴리스) : 초기화 : 398µs (예, 마이크로 초), 채우기 : 152ms

총 실행 시간 : C # : 289ms, C ++ 152ms (약 90 % 더 빠름)

관찰

  • C # 구현을 동일한 1d 배열 구현으로 변경하면 Init : 40ms, Fill : 171ms, Total : 211ms가 발생했습니다 ( C ++은 여전히 ​​거의 40 % 빠릅니다 ).

  • C ++에서 “빠른”코드를 디자인하고 작성하는 것이 어느 언어로든 “일반”코드를 작성하는 것보다 훨씬 어렵습니다.

  • C ++에서 성능이 저하되는 것은 놀랍도록 쉽습니다. 우리는 예약되지 않은 벡터 성능으로 그것을 보았습니다. 그리고 이런 함정이 많이 있습니다.

  • C #의 성능은 런타임에 진행되는 모든 것을 고려할 때 다소 놀랍습니다. 그리고 그 성능은 비교적 접근하기 쉽습니다.

  • C ++과 C #의 성능을 비교 한 일화적인 데이터 : https://benchmarksgame.alioth.debian.org/u64q/compare.php?lang=gpp&lang2=csharpcore

결론적으로 C ++은 성능을 훨씬 더 잘 제어 할 수 있다는 것입니다. 포인터를 사용 하시겠습니까? 참조? 스택 메모리? 더미? 동적 다형성 또는 정적 다형성 (템플릿 / CRTP를 통해)으로 vtable의 런타임 오버 헤드를 제거합니까? 당신이 … 어이 C ++에서 얻을 이상적으로 너무 솔루션 최선 주소 문제가 당신에게있는 거 태클이 (더) 자신이 모든 선택을 할 수 있도록.

위의 사소한 예에서도 성능이 크게 개선되었지만 액세스에 더 많은 투자가 필요하다는 것을 알 수 있기 때문에 실제로 해당 제어를 원하거나 필요로하는지 자문 해보십시오.


답변

내 경험 (그리고 두 언어로 많은 일을했습니다)에서 C ++과 비교 한 C #의 주요 문제는 높은 메모리 소비이며 제어 할 수있는 좋은 방법을 찾지 못했습니다. .NET 소프트웨어의 속도를 늦추는 것은 메모리 소비였습니다.

또 다른 요소는 JIT 컴파일러가 런타임에 실행되기 때문에 고급 최적화를 수행하는 데 너무 많은 시간을 할애 할 수 없으며 최종 사용자가 시간이 너무 오래 걸리면이를 알 수 있다는 것입니다. 반면에 C ++ 컴파일러는 컴파일 타임에 최적화를 수행하는 데 필요한 모든 시간을 갖습니다. 이 요소는 메모리 소비보다 훨씬 덜 중요합니다 (IMHO).


답변

C ++이 여전히 우위에 있고 (수년 동안) 앞으로 다가올 결정이 컴파일 타임에 사전 결정될 수있을 때 발생하는 특정 시나리오입니다.

일반적으로 캡슐화 및 지연된 의사 결정은 코드를보다 역동적이고 변화하는 요구 사항에 쉽게 적용하고 프레임 워크로 사용하기 쉽기 때문에 좋습니다. 이것이 C #의 객체 지향 프로그래밍이 매우 생산적이고 “일반화”라는 용어로 일반화 될 수있는 이유입니다. 불행하게도, 이러한 특정 종류의 일반화는 런타임에 비용이 발생합니다.

일반적으로이 비용은 실질적이지 않지만 가상 메소드 호출 및 오브젝트 작성의 오버 헤드로 인해 차이가 발생할 수있는 애플리케이션이 있습니다 (특히 가상 메소드가 메소드 호출 인라이닝과 같은 다른 최적화를 방해하므로). 당신이없는 일반화 다른 종류의 달성하기 위해 템플릿을 사용할 수 있기 때문에 C ++는 큰 장점을 가지고있는 곳이다 런타임에 영향을하지만 반드시 덜 다형성 OOP 이상입니다. 실제로 OOP를 구성하는 모든 메커니즘은 템플릿 기술과 컴파일 타임 해상도 만 사용하여 모델링 할 수 있습니다.

이러한 경우 (그리고 종종 특수한 문제 영역으로 제한됨), C ++는 C # 및 유사한 언어에 대해 승리합니다.


답변

C ++ (또는 그 문제에 대한 C)를 사용하면 데이터 구조를 세밀하게 제어 할 수 있습니다. 비트 트위스 티를 원하면 해당 옵션이 있습니다. Java / .NET 라이브러리의 내부 데이터 구조를 사용하는 대규모 관리 Java 또는 .NET 앱 (OWB, Visual Studio 2005 )은 수하물을 가지고 다닙니다. 큐브 또는 ETL 디자인을 위해 400MB가 넘는 RAM과 BIDS를 사용하는 OWB 디자이너 세션도 100MB에 도달하는 것을 보았습니다 .

예측 가능한 워크로드 (예 : 프로세스를 여러 번 반복하는 대부분의 벤치 마크와 같은)에서 JIT는 실질적인 차이가 없을 정도로 충분히 최적화 된 코드를 얻을 수 있습니다.

큰 응용 프로그램의 IMO는 코드 자체가 사용하는 데이터 구조만큼 큰 차이가 아닙니다. 응용 프로그램의 메모리가 많은 경우 캐시 사용 효율이 떨어집니다. 최신 CPU의 캐시 미스는 상당히 비쌉니다. C 또는 C ++가 실제로이기는 곳은 CPU 캐시와 잘 작동하도록 데이터 구조 사용을 최적화 할 수있는 곳입니다.