Тест C ++ против Java, нереальные результаты - PullRequest
2 голосов
/ 27 сентября 2011

Я сделал простой тест, я знаю, что C ++ быстрее, но результаты моего теста нереалистичны.

Код C ++:

#include <stdio.h>
#include <windows.h>

unsigned long long s(unsigned long long n)
{
    unsigned long long s = 0;

    for (unsigned long long i = 0; i < n; i++)
        s += i;

    return s;
}

int main()
{
    LARGE_INTEGER freq, start, end;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&start);

    printf("%llu\n", s(1000000000));

    QueryPerformanceCounter(&end);
    double d = (double) (end.QuadPart - start.QuadPart) / freq.QuadPart * 1000.0;

    printf("Delta: %f\n", d);

    return 0;
}

Код Java:

public class JavaApplication5 {

    public static long s(long n) {
        long s = 0;

        for (long i = 0; i < n; i++) {
            s += i;
        }

        return s;
    }

    public static void main(String[] args) {

        long start = System.nanoTime();

        System.out.println(s(1000000000));

        long end = System.nanoTime();

        System.out.println((end - start)/1000000);
    }
}

Компилятор C ++: gcc 4.4.0 и Java: jdk 1.6.0

Java: 2795 ms

C++ : 0.013517 ms

Там написано, что C ++ в 206777 раз быстрее, чем Java!Ни за что!Что не так в моем тесте?

Ответы [ 3 ]

6 голосов
/ 27 сентября 2011

Показать параметры компилятора, которые вы использовали.И ваш РЕАЛЬНЫЙ код (#include <stdio> не ваш реальный код).

Ваш компилятор C ++ намного умнее вашего компилятора Java (в среднем это так и в вашем случае, но не каждый компилятор C ++ умнеечем каждый Java-компилятор), и он предварительно вычислил результат.Единственное, что вы синхронизируете - это вызов printf.

В большинстве задач, для которых используется Java, он работает примерно так же, как и на языках C ++.

VM (Java, C #) несут дополнительные расходы, связанные с JIT-компиляцией, но также выигрывают от более эффективного распределения памяти и встраивания между общими библиотеками.А C ++ намного быстрее обращается к системным вызовам ОС.Кроме того, макеты памяти C ++ могут быть тщательно настроены для поведения кэша;вы не получаете такого уровня контроля в управляемых языках.

Какой из этих факторов имеет большее влияние, полностью зависит от приложения.Любой, кто делает общее заявление о том, что «C ++ в целом быстрее, чем Java» или «Java в целом быстрее, чем C ++», является идиотом.Средние значения не имеют значения.Производительность ВАШЕГО приложения имеет значение.


И вот мое доказательство того, что gcc предварительно вычисляет ответ.

Для этого кода:

#include <stdio.h>
#include <windows.h>

unsigned long long s(unsigned long long n)
{
    unsigned long long s = 0;

    for (unsigned long long i = 0; i < n; i++)
        s += i;

    return s;
}

int main( int argc, char** argv )
{
    LARGE_INTEGER freq, start, end;
    QueryPerformanceFrequency(&freq);
    QueryPerformanceCounter(&start);

    printf("%llu\n", s(1000000000));

    QueryPerformanceCounter(&end);
    double d = (double) (end.QuadPart - start.QuadPart) / freq.QuadPart * 1000.0;

    printf("Delta: %f\n", d);

    QueryPerformanceCounter(&start);

    printf("%llu\n", s(atol(argv[1])));

    QueryPerformanceCounter(&end);
    d = (double) (end.QuadPart - start.QuadPart) / freq.QuadPart * 1000.0;

    printf("Delta: %f\n", d);
    return 0;
}

С помощью gcc-4.3.4, используя командную строку ./g++-4 -omasoud-gcc.exe -O3 masoud.cpp:

bash-3.2# ./masoud-gcc 1000000000
499999999500000000
Delta: 0.845755
499999999500000000
Delta: 1114.105866

Для сравнения: MSVC ++ 16.00.40219.01 для x64 (2010 SP1), командная строка cl /Ox masoud.cpp:

> masoud 1000000000
499999999500000000
Delta: 229.684364
499999999500000000
Delta: 354.275606

VC ++ не предварительно вычисляет ответ, но 64-битный код выполняет цикл более чем в три раза быстрее.Это скорость, к которой должна приблизиться Java.


Более интересные факты: gcc предварительно вычисляет ответ быстрее, чем код, который он генерирует для его вычисления.Время компиляции для gcc:

real    0m0.886s
user    0m0.248s
sys     0m0.185s
2 голосов
/ 27 сентября 2011

Я думаю, что gcc скомпилировал ваш s метод в:

unsigned long long s(unsigned long long n)
{    
    return n*(n+1)/2;
}

... в то время как Java JIT не сделал.

Я не эксперт, но процесс оптимизации gcc может содержать больше проходов, чем может сделать JIT за разумное время. Вот почему компиляция gcc может занять много времени, в то время как java-программа запускается сразу (хотя JIT должен скомпилировать, связать и оптимизировать все, прежде чем программа сможет быть запущена).

Компилятор java (javac) выполняет очень мало оптимизаций, например, постоянное сворачивание, но это почти все. Каждая основная оптимизация (встраивание и т. Д.) Выполняется JIT, поэтому, если он не хочет, чтобы пользователь слишком долго ждал перед запуском, он должен спешить. С другой стороны, поскольку gcc компилирует и оптимизирует все статически, это может занять столько времени, сколько потребуется.

EDIT:

Должно быть просто узнать, есть ли разница в оптимизации: запустите две ваши программы с s (1000), а затем с s (100000000000000). Если я не ошибаюсь, программа на c ++ может занять одинаковое время для обоих вызовов, в то время как на выполнение программы java во втором случае потребуется больше времени.

0 голосов
/ 27 сентября 2011

Прежде всего, вы, вероятно, не захотите, чтобы соответствующие функции печати были частью вашего теста, если вы действительно не заботитесь о том, насколько они быстры.

Нет однозначного ответа относительно того, является ли Java или C ++быстрее ... это зависитJava может быть быстрее, когда компилятор может выполнить некоторые оптимизации, которые были бы недоступны для C ++.Так что это зависит от того, что конкретно вы делаете и какие параметры компилятора.

...