Компилятор против интерпретатора | Почему C более эффективен, чем Python

Вы часто слышите, что C / C ++ более эффективен, чем интерпретируемые языки, такие как Python и Node.js. В следующем посте я попытаюсь объяснить одну из многих причин, по которым скомпилированные языки, такие как C / C ++, более производительны. Прежде чем мы сможем говорить о преимуществах компиляторов, важно, чтобы вы имели базовое представление о современной компьютерной архитектуре.

Производительность процессора можно измерить в инструкциях за такт или в IPC. Есть два основных метода использования параллелизма на уровне команд для достижения более высокого IPC.

1. Глубина трубопровода

Трубопроводы аналогичны стирке.

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

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

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

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

2. Ширина трубопровода

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

Допустим, у нас есть следующая программа сборки.

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

На итерацию цикла требуется четыре тактовых цикла. Если вы посчитаете, вы получите IPC 1,25 по сравнению с 2,0, которого мы могли бы достичь, если бы полностью использовали дополнительное оборудование.

Развертывание петли

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

Обратите внимание, что теперь 12 из 14 инструкций в цикле выполняются как пары. Требуется 8 тактов для 4 итераций цикла или 2 такта на итерацию, что дает IPC 14/8 = 1,75. Это 1,75 - 1,25 / 1,75 = 29% увеличения скорости по сравнению с предыдущим примером.

Заключение

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