Скомпилированный по сравнению с интерпретируемыми языками

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

Большинство моих событий программирования было с CPython (динамично, интерпретировано), и Java (статичный, скомпилированный). Однако я понимаю, что существуют другие виды интерпретируемых и скомпилированных языков. Кроме того, что исполняемые файлы могут быть распределены из программ, записанных на скомпилированных языках, там какие-либо преимущества/недостатки для каждого типа? Часто, я слышу, что люди утверждают, что интерпретируемые языки могут использоваться в интерактивном режиме, но я полагаю, что скомпилированные языки могут иметь интерактивные реализации также, корректный?

263
задан starblue 18 July 2010 в 05:15
поделиться

7 ответов

Скомпилированный язык - это язык, на котором однажды скомпилированная программа выражается в инструкциях целевой машины. Например, операция добавления «+» в исходном коде может быть преобразована непосредственно в инструкцию «ADD» в машинном коде.

Интерпретируемый язык - это язык, в котором инструкции не выполняются непосредственно целевой машиной, а вместо этого читаются и выполняются какой-либо другой программой (которая обычно написана на языке собственной машины). Например, та же операция «+» будет распознана интерпретатором во время выполнения, который затем вызовет свою собственную функцию «add (a, b)» с соответствующими аргументами, которая затем выполнит инструкцию машинного кода «ADD». .

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

Я собираюсь полностью обобщить (пуристы меня простят!), Но, грубо говоря, вот преимущества компилируемых языков:

  • Более высокая производительность за счет прямого использования собственного кода целевой машины
  • Возможность применения довольно мощная оптимизация на этапе компиляции

И вот преимущества интерпретируемых языков:

  • Легче реализовать (писать хорошие компиляторы очень сложно !!)
  • Нет необходимости запускать этап компиляции: можно выполнять код напрямую » на лету »
  • Может быть более удобным для динамических языков

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

437
ответ дан 23 November 2019 в 02:29
поделиться

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

Традиционно «скомпилированный» означает, что этот перевод выполняется за один раз, выполняется разработчиком, а полученный исполняемый файл распространяется среди пользователей. Чистый пример: C ++. Компиляция обычно занимает довольно много времени и пытается выполнить множество дорогостоящих оптимизаций, чтобы получившийся исполняемый файл работал быстрее. Конечные пользователи не имеют инструментов и знаний для самостоятельной компиляции, а исполняемый файл часто должен работать на различном оборудовании, поэтому вы не можете выполнять много оптимизаций для конкретного оборудования. Во время разработки отдельный этап компиляции означает более длительный цикл обратной связи.

Традиционно «интерпретируемый» означает, что перевод происходит «на лету», когда пользователь хочет запустить программу. Чистый пример: ванильный PHP.Наивный интерпретатор должен анализировать и переводить каждый фрагмент кода при каждом запуске, что делает его очень медленным. Он не может выполнять сложные и дорогостоящие оптимизации, потому что они займут больше времени, чем время, сэкономленное при выполнении. Но он может полностью использовать возможности оборудования, на котором работает. Отсутствие отдельного этапа компиляции сокращает время обратной связи во время разработки.

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

7
ответ дан 23 November 2019 в 02:29
поделиться

Во-первых, уточнение: Java не является полностью статически компилируемой и компонуемой, как C++. Она компилируется в байткод, который затем интерпретируется JVM. JVM может пойти и сделать компиляцию just-in-time в родной машинный язык, но не обязана этого делать.

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

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

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

Что касается генерации исполняемых файлов, то это имеет мало общего с этим, ИМХО. Вы часто можете создать исполняемый файл из скомпилированного языка. Но вы также можете создать исполняемый файл из интерпретируемого языка, за исключением того, что интерпретатор и среда выполнения уже упакованы в исполняемый файл и скрыты от вас. Это означает, что вы, как правило, все равно платите за время выполнения (хотя я уверен, что для некоторых языков есть способы перевести все в древовидный исполняемый файл).

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

.
4
ответ дан 23 November 2019 в 02:29
поделиться

Сам язык не компилируется и не интерпретируется, только его конкретная реализация. Java - прекрасный пример. Существует платформа на основе байткодов (JVM), компилятор родного языка (gcj) и интерпретатор для супермножества Java (bsh). Так что же такое Java сейчас? Скомпилированная на байткоде, с родным компилятором или интерпретируемая?

Другие языки, которые являются как компилируемыми, так и интерпретируемыми, - это Scala, Haskell или Ocaml. Каждый из этих языков имеет интерактивный интерпретатор, а также компилятор в байт-код или нативный машинный код.

Так что в целом классификация языков на "компилируемые" и "интерпретируемые" не имеет особого смысла.

95
ответ дан 23 November 2019 в 02:29
поделиться

Крайний и простой случаи:

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

  • Интерпретатор представляет пользователю подсказку в цикле, где он может вводить операторы или код, и после нажатия RUN или аналогичного средства интерпретатор будет исследовать, сканировать, анализировать и интерпретировать каждую строку до тех пор, пока программа работает до точки остановки или до ошибки. Поскольку каждая строка обрабатывается сама по себе, и интерпретатор ничего не «узнает» из того, что видел строку раньше, усилия по преобразованию понятного человеку языка в машинные инструкции возникают каждый раз для каждой строки, так что это очень медленно. С другой стороны, пользователь может проверять свою программу и иным образом взаимодействовать с ней разными способами: изменять переменные, изменять код, работать в режимах трассировки или отладки ...

Теперь позвольте мне объяснить, что жизнь уже не так проста.Например,

  • Многие интерпретаторы предварительно компилируют предоставленный им код, поэтому шаг перевода не нужно повторять снова и снова.
  • Некоторые компиляторы компилируют не машинные инструкции, специфичные для процессора, а байт-код, своего рода искусственный машинный код для фиктивной машины. Это делает скомпилированную программу немного более переносимой, но требует наличия интерпретатора байт-кода в каждой целевой системе.
  • Интерпретаторы байт-кода (я здесь смотрю на Java) в последнее время склонны повторно компилировать байт-код, который они получают для ЦП целевой секции непосредственно перед выполнением (так называемый JIT). Чтобы сэкономить время, это часто делается только для кода, который часто выполняется (горячие точки).
  • Некоторые системы, которые выглядят и действуют как интерпретаторы (например, Clojure), немедленно компилируют любой код, который они получают, но предоставляют интерактивный доступ к среде программы. Это в основном удобство интерпретаторов со скоростью двоичной компиляции.
  • Некоторые компиляторы на самом деле не компилируются, они просто предварительно переваривают и сжимают код. Некоторое время назад я слышал, как работает Perl. Так что иногда компилятор просто выполняет небольшую работу, и большая часть ее остается интерпретацией.

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

25
ответ дан 23 November 2019 в 02:29
поделиться

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

2
ответ дан 23 November 2019 в 02:29
поделиться

Начните думать с точки зрения: взрыва из прошлого

Когда-то давным-давно жили в стране компьютеров интерпретаторы и компиляторы. Возникла всякая возня по поводу достоинств один над другим. Общее мнение в то время было примерно таким:

  • Интерпретатор: Быстро разрабатывать (редактировать и запускать). Медленно выполнять, потому что каждый оператор нужно было интерпретировать в машинный код каждый раз, когда он выполнялся (подумайте, что это значило для цикла, выполняемого тысячи раз).
  • Компилятор: медленно разрабатывать (редактировать, компилировать, связывать и запускать. Этапы компиляции / компоновки могут занять много времени). Быстрый выполнить. Вся программа была уже в машинном коде.

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

Сегодня ландшафт изменился до такой степени, что компилируемое / интерпретируемое различие в значительной степени не имеет отношения к делу. Многие скомпилированные языки вызывают службы времени выполнения, которые не полностью на основе машинного кода. Кроме того, большинство интерпретируемых языков «компилируются» в байт-код. перед казнью. Интерпретаторы байтового кода могут быть очень эффективными и конкурировать с некоторыми компиляторами. код с точки зрения скорости выполнения.

Классическое отличие состоит в том, что компиляторы генерируют машинный код в машинном коде, интерпретаторы читают исходный код и сгенерированный машинный код на лету с использованием какой-то системы времени выполнения. Сегодня осталось совсем немного классических интерпретаторов - почти все. компилировать в байт-код (или другое полукомпилированное состояние), который затем запускается на виртуальной «машине».

51
ответ дан 23 November 2019 в 02:29
поделиться
Другие вопросы по тегам:

Похожие вопросы: