Почему скомпилированные языки не работают одинаково, если они в конечном итоге становятся машинным кодом?
Если, например, C#, Java или c++ компилируются в машинный код, почему они не одинаково эффективны?
Я понимаю, что такие языки являются абстракцией машинного кода, к которому они все в конечном итоге компилируются. Разве процессор не должен определять производительность?
5 ответов
во-первых, оптимизаторы C++ намного более зрелые. Во-вторых, производительность всегда была главной целью разработчиков языка C++ ("вы не платите за то, что не используете"-это мантра, которую явно нельзя сказать о политике Java every-method-is-virtual).
помимо этого, шаблоны C++ гораздо более удобны для оптимизации, чем Java или C# generics. Хотя JITs часто хвалят за их способность оптимизировать через границы модуля, generics останавливает это мертвое по своим следам. Среда CLR (среда выполнения .NET) создает только одну версию машинного кода для универсального кода, который охватывает все ссылочные типы. С другой стороны, оптимизатор C++ работает для каждой комбинации параметров шаблона и может выполнять встроенные зависимые вызовы.
далее с C# и Java у вас есть очень мало контроля над памятью. Параллельные алгоритмы могут страдать от снижения производительности на порядок из-за ложного совместного использования строк кэша, и почти ничего, что разработчик могу с этим поделать. OTOH C++ предоставляет инструменты для размещения объектов на определенных смещениях относительно страниц ОЗУ и границ кэша.
рассмотрите различия в языках и накладные расходы, которые это происходит - даже если такая дополнительная работа выполняется "с той же эффективностью", есть просто больше, чтобы сделать. Период. (Это цена, которая часто приходит с абстракцией: время разработки может быть [существенно] уменьшено для [умеренного] увеличения времени выполнения.)
с другой стороны, с тривиальной функцией, не использующей "языковых функций", таких как цикл вычисления факториала ... тогда цифры может стать очень конкурсный в некоторых случаях. Это можно увидеть в Компьютерный Язык Бенчмарк Игры (здесь Java7 против C++, например).
отметим, что реализация языка (включая JIT) и применяемые оптимизации ("-Ox") также являются основным фактором. (Язык, возможно," не имеет скорости " сам по себе.)
удачи в кодировании.
Как было указано Voigt, модели JIT/AOT оптимизированы для различные аспекты. (The Солнце реализация Oracle Java даже имеет отдельный сервер VM и клиент VM, каждый из которых приоритизирует разные варианты использования.) Вот некоторые сообщения, обсуждающие JIT против AOT:
" Если C#, Java или C++, например, все в конечном итоге компилируются в машинный код, почему они не одинаково эффективны?"
и C#, и Java компилируются в байт-код, который в конечном итоге сводится к машинному коду виртуальной машиной (например, для Java его называют JVM). Однако C++, как правило, изначально компилируется до уровня сборки.
виртуальные машины на самом деле могут выполнять определенные оптимизации во время выполнения (например, bimorphic встраивание), но и в других случаи добавленные накладные расходы отрицательно влияют на производительность
знаете ли вы, что один и тот же код C++ не создает один и тот же машинный код с разными компиляторами или разными версиями одного и того же компилятора? Некоторые компиляторы будут использовать тот же источник и создавать двоичный файл для той же цели, что и другой компилятор. По тем же причинам другие языки, которые компилируются в машинный код не будет делать то же самое. Некоторые языки легче компилировать/оптимизировать, чем другие. Такие языки, как Java, не сравниваются, поскольку они не компиляция в машинный код они обычно компилируются в независимый от системы байт-код, а затем запускаются на виртуальной машине jvm. jvm - это некоторый код на некотором языке, скомпилированный некоторым компилятором, который может быть быстрым или медленным в зависимости от выбранного кода и компилятора. интерпретируемые языки, такие как java (байт-код), медленны по сравнению с компиляцией непосредственно в машинный код.
потратьте некоторое время, чтобы узнать, как разобрать двоичные файлы, которые вы скомпилировали. Прочитайте инструкцию по типу байт-кода устанавливает за java, python и т. д. p-код, который использовал Паскаль, и т. д.
Если вы говорите о компьютерах x86, у вас есть огромная разница в производительности в этом семействе. Вы можете скомпилировать двоичный файл, который работает очень быстро относительно тактовой частоты на одном процессоре x86, но тот же двоичный файл работает очень медленно на другом, обычно более новый процессор с более быстрой тактовой частотой работает более старый двоичный файл медленнее. В мире x86 это тщетные усилия по созданию одного двоичного файла, который работает быстрый везде, поэтому ваш компилятор, если производительность желательна, должен работать значительно сложнее, чтобы попытаться нацелить производительность на систему/процессор.
ваш вопрос похож на вопрос, если все транспортные средства в основном имеют двигатель и четыре колеса, почему некоторые могут идти быстрее? Почему одни перевозят больше, чем другие?
Если 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 завершает компиляцию, время падает с 4609ms до 563ms.
Java код 8 раз быстрее чем наивное измерение заставило бы вас поверить.