Почему скомпилированные языки не работают одинаково, если они в конечном итоге становятся машинным кодом? - PullRequest
12 голосов
/ 03 октября 2011

Если C #, Java или C ++, например, все компилируются в машинный код, почему они не одинаково производительны?

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

Ответы [ 5 ]

8 голосов
/ 03 октября 2011

С одной стороны, оптимизаторы C ++ гораздо более зрелые.Во-вторых, производительность всегда была главной целью разработчиков языка C ++ («вы не платите за то, что не используете») - это мантра, чего явно нельзя сказать о политике «каждый метод является виртуальным» в Java.).

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

Далее, с C # и Java у вас очень мало контроля над макетом памяти.Параллельные алгоритмы могут пострадать на порядок ухудшения производительности из-за ложного разделения строк кэша, и разработчик почти ничего не может с этим поделать.OTOH C ++ предоставляет инструменты для размещения объектов с определенным смещением относительно страниц ОЗУ и границ кэша.

6 голосов
/ 03 октября 2011

Примите во внимание различия в языках и накладные расходы, которые возникают - даже если такая дополнительная работа выполняется «с той же эффективностью», еще многое предстоит сделать.Период.(Это цена, которая часто приходит с абстракцией: время разработки может быть [существенно] уменьшено для [умеренного] увеличения времени выполнения.)

С другой стороны, с тривиальной функцией, не использующей «языковые функции»«Например, цикл вычисления факториала ... тогда числа могут стать очень конкурентоспособными в некоторых случаях.Это можно увидеть в тесте по языку программирования (здесь, например, Java7 против C ++ ).

Обратите внимание, что реализация языка (включая JIT) и применяемые оптимизации ("-Ox") также является важным фактором.(Язык, по-видимому, «не имеет скорости» сам по себе.)

Удачное кодирование.


Как указывал Беен Фойгт, модели JIT / AOT оптимизированы для различных аспектов.(В реализации Java * Sun даже есть отдельная виртуальная машина сервера и клиентская виртуальная машина, каждая из которых определяет приоритет использования различий.) Вот несколько сообщений SO, в которых обсуждается JIT против AOT:

5 голосов
/ 03 октября 2011

"Если C #, Java или C ++, например, все в итоге компилируются в машинный код, почему они не одинаково производительны?"

И C #, и Java компилируются в байт-код, который в конечном итоге преобразуется в машинный код виртуальной машиной (например, для Java она называется JVM). Однако C ++ изначально компилируется до уровня сборки.

Виртуальные машины могут фактически выполнять определенную оптимизацию во время выполнения (один из распространенных примеров - биморфное встраивание), но в других случаях дополнительные издержки отрицательно влияют на производительность

3 голосов
/ 05 октября 2011

Знаете ли вы, что один и тот же код C ++ не создает один и тот же машинный код с разными компиляторами или разными версиями одного и того же компилятора? Некоторые компиляторы берут один и тот же исходный код и создают двоичный файл для той же цели, который значительно быстрее, чем другой компилятор. По тем же причинам другие языки, которые компилируются в машинный код, не будут выполнять то же самое. Некоторые языки легче компилировать / оптимизировать, чем другие. Такие языки, как Java, не сравниваются, поскольку они не компилируются с машинным кодом, они обычно компилируются в независимый от системы байт-код и затем запускаются на виртуальной машине jvm. jvm - это некоторый код на некотором языке, скомпилированный некоторым компилятором, который может быть быстрым или медленным в зависимости от выбранного кода и компилятора. интерпретируемые языки, такие как Java (байт-код), медленнее по сравнению с компилируемыми непосредственно в машинный код.

Потратьте некоторое время, чтобы научиться разбирать скомпилированные вами двоичные файлы. Читайте о наборе инструкций типа байт-кода позади p-кода java, python и т. Д., Который использовал pascal и т. Д., И т. Д.

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

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

2 голосов
/ 16 октября 2011

Если, например, C #, Java или C ++, все в конечном итоге компилируются в машинный код, почему они не одинаково производительны?

Проще говоря - не все они компилируются в тот же машинный код.

Обратите внимание на то, что многие претензии по поводу производительности, которые вы увидите в Интернете, будут неверными, а многие измеренияпроизводительности, которую вы увидите в Интернете, устарели, ненадежны или сломаны каким-либо другим способом.

Например, phresnel указал на измерения крошечной программы умножения , иэти измерения были:

  • , сделанные с использованием Java 1.4 в 2003 году - текущая версия Java 7

  • , выполненная очень наивным способом, который предотвратилJava после завершения компиляции

Давайте просто запустим его программу полдюжины раз без перезапуска JVM и посмотрим, что произойдет:

public class mult {

    public static void main(String[] args){
        for (int i=0; i<6; ++i) mult.program_main(args);
   }

    public static void program_main(String[] args) {
        long nbStep = 1000000000;
        long tCPU = System.currentTimeMillis();
        double t=1. , r= 0.9999999999999999999999999999999999;

        if ( args.length > 0 ) {
            nbStep = Integer.parseInt(args[0]);
            System.out.println( args[0] + " demandees" );
        }
        for ( long i = 0; i < nbStep; i++ ) {
            t = t * r;
        }
        tCPU = - tCPU + System.currentTimeMillis();
        System.out.println(nbStep + " multiplications en " +
            tCPU + " millisecondes ." );
    }
}


$ /usr/local/src/jdk1.7.0/bin/java -XX:+PrintCompilation -XX:+PrintGC mult
     53    1 %           mult::program_main @ 57 (122 bytes)
   4662    1 %           mult::program_main @ -2 (122 bytes)   made not entrant
1000000000 multiplications en 4609 millisecondes .
   4662    1             mult::program_main (122 bytes)
   4669    2 %           mult::program_main @ 57 (122 bytes)
1000000000 multiplications en 4612 millisecondes .
1000000000 multiplications en 564 millisecondes .
1000000000 multiplications en 563 millisecondes .
1000000000 multiplications en 563 millisecondes .
1000000000 multiplications en 563 millisecondes .

После завершения Javaкомпиляция времена упали с 460От 9 мс до 563 мс.

Java-код в 8 раз быстрее , чем наивные измерения, как вы могли бы поверить.

...