почему это простое добавление C ++ в 6 раз медленнее, чем эквивалентное Java?

привет, пользователи stackoverflow, это мой первый вопрос, поэтому, если у меня есть какие-либо ошибки в моем выражении, пожалуйста, укажите это, спасибо

Я написал эту простую функцию вычисления на Java и C ++

Джава:

long start = System.nanoTime();
long total = 0;
for (int i = 0; i < 2147483647; i++) {
total += i;
}
System.out.println(total);
System.out.println(System.nanoTime() - start);

C ++:

auto start = chrono::high_resolution_clock::now();
register long long total = 0;
for (register int i = 0; i < 2147483647; i++)
{
total += i;
}
cout << total << endl;
auto finish = chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::nanoseconds>(finish - start).count() << endl;

программного обеспечения:
— JDK8u11
— Microsoft Visual C ++ Compiler (2013)

Результаты:

Джава:
2305843005992468481
1096361110

C ++:
2305843005992468481
6544374300

Результаты расчета одинаковы, что хорошо
однако напечатанное время nano показывает, что Java-программе требуется 1 секунда, в то время как в C ++ для ее выполнения требуется 6 секунд.

Я давно занимаюсь Java, но я новичок в C ++, есть ли проблемы в моем коде? или это факт, что C ++ медленнее, чем Java с простыми вычислениями?

Кроме того, я использовал ключевое слово «register» в своем коде на C ++, надеясь, что это принесет улучшение производительности, но время выполнения совсем не отличается, может кто-нибудь объяснить это?

РЕДАКТИРОВАТЬ: Моя ошибка здесь заключается в том, что настройки компилятора C ++ не оптимизированы, и вывод устанавливается на x32, после применения / O2 WIN64 и удаления DEBUG, выполнение программы заняло всего 0,7 секунды

JDK по умолчанию применяет оптимизацию к выводу, однако это не относится к VC ++, который по умолчанию предпочитает скорость компиляции, разные компиляторы C ++ также различаются по результату, некоторые вычисляют результат цикла во время компиляции, что приводит к чрезвычайно короткому времени выполнения ( около 5 микросекунд)

ПРИМЕЧАНИЕ. При правильных условиях программа C ++ будет работать лучше, чем Java, в этом простом тесте, однако я заметил, что многие проверки безопасности во время выполнения пропускаются, нарушая намерение отладки как «безопасный язык», и я считаю, что C ++ будет еще превосходить Java в тест большого массива, так как он не имеет проверки границ

3

Решение

В Linux / Debian / Sid / x86-64, используя OpenJDK 7 с

// file test.java
class Test {
public static void main(String[] args) {
long start = System.nanoTime();
long total = 0;
for (int i = 0; i < 2147483647; i++) {
total += i;
}
System.out.println(total);
System.out.println(System.nanoTime() - start);
}
}

и GCC 4.9 с

   // file test.cc
#include <iostream>
#include <chrono>

int main (int argc, char**argv) {
using namespace std;
auto start = chrono::high_resolution_clock::now();
long long total = 0;
for (int i = 0; i < 2147483647; i++)
{
total += i;
}
cout << total << endl;
auto finish = chrono::high_resolution_clock::now();
cout << chrono::duration_cast<chrono::nanoseconds>(finish - start).count()
<< endl;
}

Затем компилирование и запуск test.java с

javac test.java
java Test

Я получаю вывод

2305843005992468481
774937152

при компиляции test.cc с оптимизацией

g++ -O2 -std=c++11 test.cc -o test-gcc

и работает ./test-gcc это идет намного быстрее

2305843005992468481
40291

Конечно без оптимизаций g++ -std=c++11 test.cc -o test-gcc бег медленнее

2305843005992468481
5208949116

Глядя на ассемблерный код, используя g++ -O2 -fverbose-asm -S -std=c++11 test.cc Я вижу, что компилятор вычислил результат во время компиляции:

    .globl  main
.type   main, @function
main:
.LFB1530:
.cfi_startproc
pushq   %rbx    #
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
call    _ZNSt6chrono3_V212system_clock3nowEv    #
movabsq $2305843005992468481, %rsi  #,
movl    $_ZSt4cout, %edi    #,
movq    %rax, %rbx  #, start
call    _ZNSo9_M_insertIxEERSoT_    #
movq    %rax, %rdi  # D.35007,
call    _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_  #
call    _ZNSt6chrono3_V212system_clock3nowEv    #
subq    %rbx, %rax  # start, D.35008
movl    $_ZSt4cout, %edi    #,
movq    %rax, %rsi  # D.35008, D.35008
call    _ZNSo9_M_insertIlEERSoT_    #
movq    %rax, %rdi  # D.35007,
call    _ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_  #
xorl    %eax, %eax  #
popq    %rbx    #
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE1530:
.size   main, .-main

Так что вам просто нужно включить оптимизацию в вашем компиляторе (или переключиться на лучший компилятор, как НКУ 4,9)

Кстати, на Java оптимизации низкого уровня происходят в JIT из JVM. Я плохо знаю JAVA, но не думаю, что мне нужно их включать. Я знаю, что в GCC вы должны включить оптимизацию, которая, конечно, досрочно (например, с -O2)

PS: Я никогда не использовал компилятор Microsoft в этом 21-м веке, поэтому я не могу помочь вам в том, как включить в него оптимизацию.

Наконец, я не верю, что такие микробенчмарки значимы. Затем вы сможете оптимизировать ваши реальные приложения.

7

Другие решения

Занимает около 0,6 секунды (.592801000 секунд) в моей системе, Intel 2600K, 3,40 ГГц, с MSVC Express 2013, 64-разрядный режим, стандартная сборка выпуска. После установки финиша cout перемещен, чтобы не включать накладные расходы cout.

#include <iostream>
#include <chrono>

using namespace std;

int main()
{
auto start = chrono::high_resolution_clock::now();
register long long total = 0;
for (register int i = 0; i < 2147483647; i++)
{
total += i;
}
auto finish = chrono::high_resolution_clock::now();
cout << total << endl;
cout << chrono::duration_cast<chrono::nanoseconds>(finish - start).count() << endl;
return 0;
}
0

Я думаю, что самый простой способ описать, почему C / C ++ ВСЕГДА будет быстрее, чем Java, это понять, как работает Java.

С самого начала Java была разработана для облегчения кроссплатформенного программного обеспечения. До Java нужно было скомпилировать свою программу на каждом семействе машин отдельно. Даже сейчас, с разнообразием аппаратных архитектур, принятых стандартов и ОС, никто не может обойти это препятствие. Java выполняет это с помощью своего компилятора и JVM. Компилятор применяет любую возможную оптимизацию и собирает ее в байт-код Java, что похоже на сокращенный оптимизированный источник, который был скомпилирован. Однако этот байт-код еще не может быть понят процессором.

Вот где появляется виртуальная машина Java. Сначала JVM выясняет, в какой среде она запускается, и загружает соответствующую таблицу перевода. Затем байт-код считывается в JVM, и каждый код ищется в таблице и транслируется в машинный код среды, а затем выполняется.

Как вы знаете, все это занимает немного времени на одну инструкцию. Но в случае скомпилированной программы на C / C ++ она уже находится в правильном машинном коде и выполняется немедленно.

Интересное примечание. Все операционные системы и большинство драйверов устройств написаны на языке C по соображениям производительности.

-1
По вопросам рекламы [email protected]