Компилируемые и интерпретируемые языки программирования: разница и примеры

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

Разобрали разницу на одной опечатке в C и Python, показали байт-код Python и V8 и замерили один цикл: на C он занял 0,09 секунды, на Python 8,4.

Статью написал:
Ваня Буявец, продюсер, основатель Checkroi
Ваня Буявец
Основатель Checkroi, продюсер, эксперт в выборе онлайн-курсов
Все 3221 статья автора Подписаться на Телеграм-канал
Одобрено экспертом:
Наташа Буявец, основатель Checkroi, эксперт по онлайн-курсам
Наташа Буявец
Основательница Checkroi, продюсер Youtube-каналов, эксперт по онлайн-курсам
Все 3875 экспертных мнений Подписаться на Телеграм-канал
Обложка: Компилируемые и интерпретируемые языки программирования: разница и примеры

Компилируемый язык переводят в машинный код целиком до запуска: компилятор читает весь исходник, проверяет его и выдаёт готовый исполняемый файл. Интерпретируемый язык исполняет специальная программа, интерпретатор, прямо во время работы, без отдельного шага сборки. Типичные компилируемые языки: C, C++, Go, Rust. Типичные интерпретируемые: Python, JavaScript, Ruby, PHP.

Граница давно размыта. Python перед исполнением сам компилирует код в байт-код, а JavaScript движок браузера на лету доводит до машинного кода. Поэтому «компилируемый» или «интерпретируемый» точнее говорить про реализацию языка, про конкретную программу, которая исполняет код.

Ниже разберём разницу на живых примерах, замерим скорость одного и того же цикла и ответим на вопрос из школьного теста. Где этот признак стоит среди остальных, видно в классификации языков программирования.

CheckroiCheckroiПодборка курсов по Python570 курсов • 53 школыСравните цены, школы, программу и найдите выгодные предложения по обучениюСравнить→

Главные различия в одной таблице

Рой за ноутбуком сравнивает компилятор и интерпретатор
Признак Компилируемые Интерпретируемые
Когда код переводится До запуска, один раз Во время выполнения, при каждом запуске
Что получает пользователь Исполняемый файл Исходный код, который запускает интерпретатор
Когда видны ошибки Многие ловит компилятор до запуска Когда выполнение дошло до строки с ошибкой
Скорость выполнения Обычно выше Обычно ниже, JIT сокращает разрыв
Цикл «поправил и запустил» Нужна пересборка Запускаете сразу
Переносимость Файл собран под конкретную ОС и процессор Работает там, где установлен интерпретатор
Примеры C, C++, Go, Rust, Swift Python, JavaScript, Ruby, PHP

В глоссарии Python разницу формулируют так: исходники можно запускать без явного создания исполняемого файла. Цикл разработки и отладки у интерпретируемых языков обычно короче, а программы, как правило, работают медленнее.

Там же есть оговорка: граница может быть размытой из-за компилятора байт-кода. К ней вернёмся ниже.

Как работает компилятор

Компилятор берёт файл целиком. В документации GCC сказано, что компиляция может включать до четырёх стадий, всегда в одном порядке:

  1. Препроцессинг. Подставляются заголовочные файлы и макросы, например #include <stdio.h>.
  2. Собственно компиляция. Код на C превращается в ассемблер для конкретного процессора.
  3. Ассемблирование. Из ассемблера получается объектный файл с машинными командами.
  4. Компоновка. Объектные файлы и библиотеки склеиваются в исполняемый файл.

Каждую стадию с выводом на реальном примере мы разобрали в статье о компиляции простыми словами. Здесь важнее итог: на выходе лежит самостоятельный файл, которому для запуска не нужны ни компилятор, ни исходник.

Опечатка в программе на C

Вот программа с ошибкой в пятой строке: вместо printf написано pritnf.

#include <stdio.h>

int main(void) {
    printf("Первая строка\n");
    pritnf("Вторая строка\n");
    return 0;
}

Собираем компилятором Apple clang 17:

$ clang hello.c -o hello
hello.c:5:5: error: call to undeclared function 'pritnf'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
    5 |     pritnf("Вторая строка\n");
      |     ^
hello.c:5:5: note: did you mean 'printf'?
/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/usr/include/_printf.h:34:6: note: 'printf' declared here
   34 | int      printf(const char * __restrict, ...) __printflike(1, 2);
      |          ^
1 error generated.

Первая строка программы корректна, но и она не выполнилась. Исполняемого файла нет вообще: компилятор остановил сборку до запуска.

Исправляем опечатку и собираем снова:

$ clang hello.c -o hello
$ file hello
hello: Mach-O 64-bit executable arm64
$ ./hello
Первая строка
Вторая строка

Файл hello собран под macOS и процессор Apple (arm64). На Windows или Linux он не запустится, там программу пересобирают из исходника компилятором для этой системы.

Канал основателя Checkroi Вани Буявца3 800 человек читают мой Телеграм-канал про нейросетиСобрал промпты для Claude Code и ChatGPT, разборы ИИ-инструментов и лайфхаки по продвижению бизнеса в одном местеПрисоединиться

Как работает интерпретатор

Интерпретатор не готовит файл заранее. Он читает программу и сразу выполняет её, команду за командой. Та же опечатка на Python:

print("Первая строка")
pritn("Вторая строка")

Запускаем в Python 3.14 (путь к файлу в трейсбеке сокращён до имени):

$ python3 hello.py
Первая строка
Traceback (most recent call last):
  File "hello.py", line 2, in <module>
    pritn("Вторая строка")
    ^^^^^
NameError: name 'pritn' is not defined. Did you mean: 'print'?

Разница в первой строке вывода. Python успел напечатать «Первая строка» и упал, только когда дошёл до ошибки.

Для коротких скриптов это удобно: поправили и сразу запустили. Как это выглядит на первых программах, показано в разборе Hello World на Python.

Для больших программ у такого подхода есть цена. Ошибка в редкой ветке if может месяцами жить в коде, пока кто-нибудь не пройдёт по этой ветке.

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

Как запускать скрипт из терминала, разобрано в инструкции для командной строки Windows.

Почему граница размыта: байт-код и JIT

Конвейер превращает исходный код в байт-код и машинные команды

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

Python компилирует в байт-код

По глоссарию Python, исходный код компилируется в байт-код, внутреннее представление программы в интерпретаторе CPython. Байт-код кешируется в файлах .pyc, чтобы второй запуск того же файла шёл быстрее.

Посмотреть байт-код можно модулем dis. Возьмём функцию, которая возводит число в квадрат:

def square(x):
    return x * x
$ python3 -m dis square.py
  0           RESUME                   0

  1           LOAD_CONST               0 (<code object square at 0x1051d56b0, file "square.py", line 1>)
              MAKE_FUNCTION
              STORE_NAME               0 (square)
              LOAD_CONST               1 (None)
              RETURN_VALUE

Disassembly of <code object square at 0x1051d56b0, file "square.py", line 1>:
  1           RESUME                   0

  2           LOAD_FAST_BORROW_LOAD_FAST_BORROW 0 (x, x)
              BINARY_OP                5 (*)
              RETURN_VALUE

Эти команды исполняет виртуальная машина CPython: читает по одной и выполняет. Процессор напрямую их не понимает. Команда python3 -m py_compile square.py сохраняет байт-код в файл __pycache__/square.cpython-314.pyc. При обычном импорте модуля Python делает то же сам, если запись байт-кода не отключена переменной PYTHONDONTWRITEBYTECODE.

Скорости исполнения байт-код почти не прибавляет: он экономит время на повторном разборе исходника при запуске. Про сильные и слабые стороны языка подробнее в статье о плюсах и минусах Python.

Java компилирует в байт-код для JVM

Команда javac, по документации Oracle, читает исходные файлы и компилирует их в class-файлы, которые запускаются на виртуальной машине Java.

Машинного кода для конкретного процессора на этом шаге нет. Поэтому один и тот же class-файл работает на любой системе, где установлена JVM, а она уже во время работы доводит горячий код до машинного. Чем Java отличается от почти тёзки, мы разбирали в статье о Java и JavaScript.

JavaScript: интерпретатор и JIT в одном движке

Движок V8, на котором работают Chrome и Node.js, тоже начинает с байт-кода. Флаг --print-bytecode показывает, во что превратилась функция:

function square(x) {
  return x * x;
}
console.log(square(7));
$ node --print-bytecode --print-bytecode-filter=square square.js
[generated bytecode for function: square (0x32dae56a92d1 <SharedFunctionInfo square>)]
Bytecode length: 6
Parameter count 2
Register count 0
Frame size 0
   23 S> 0x2c6e79ff8728 @    0 : 0b 03             Ldar a0
   32 E> 0x2c6e79ff872a @    2 : 42 03 00          Mul a0, FBV[0]
   36 S> 0x2c6e79ff872d @    5 : b7                Return
Constant pool (size = 0)
Handler Table (size = 0)
Source Position Table (size = 8)
0x2c6e79ff8731 <Other heap object (TRUSTED_BYTE_ARRAY_TYPE)>
49

Этот байт-код исполняет интерпретатор Ignition. Дальше подключаются компиляторы движка: в блоге V8 компилятор Sparkplug описан как ступень между интерпретатором Ignition и оптимизирующим компилятором TurboFan.

Такой подход называют JIT-компиляцией (just in time, «точно в срок»). Машинный код появляется во время работы программы и только для тех кусков, которые выполняются чаще всего.

Замер: один цикл на C, JavaScript и Python

Возьмём одну задачу и запустим её на ноутбуке с Apple M4 Pro: сложить остатки от деления на 7 для всех чисел от 0 до 200 миллионов. Ответ у всех вариантов одинаковый, 599 999 994.

// loop.c
long long total = 0;
for (long long i = 0; i < 200000000; i++) {
    total += i % 7;
}

// loop.js
let total = 0;
for (let i = 0; i < 200000000; i++) {
  total += i % 7;
}

# loop.py
total = 0
for i in range(200_000_000):
    total += i % 7

Время измеряли командой /usr/bin/time -p, в таблице поле real второго и третьего прогона из трёх, первый шёл на холодном кеше.

Вариант Как исполняется Время, с
C, clang -O2 Машинный код, собран заранее 0,09
C, clang -O0 (без оптимизаций) Машинный код, собран заранее 0,11
JavaScript, Node.js 26 Байт-код, затем JIT 0,17
JavaScript, Node.js с флагом —jitless Только интерпретатор 1,64
Python 3.14 Байт-код и интерпретатор 8,4

Что из этого следует:

  • Python на этой задаче медленнее C примерно в 90 раз: 8,4 секунды против 0,09.
  • Тот же JavaScript без JIT замедлился почти в 10 раз, с 0,17 до 1,64 секунды. В режиме --jitless, по описанию разработчиков V8, весь пользовательский код идёт через интерпретатор Ignition.
  • Узкий арифметический цикл для интерпретатора самый неудобный случай. Программа, которая ждёт сеть или базу данных, теряет намного меньше. Разработчики V8 в той же заметке приводят для режима без JIT разброс от 6 % замедления на приложении YouTube для телевизоров до 80 % на Web Tooling Benchmark.

Python тоже движется к JIT. В официальные сборки Python 3.14 для macOS и Windows вошёл экспериментальный JIT-компилятор: включается переменной PYTHON_JIT=1 и для продакшена не рекомендован. Эффект, по словам разработчиков, колеблется от замедления на 10 % до ускорения на 20 % в зависимости от задачи.

В сборке Python 3.14 из Homebrew, на которой шёл замер, JIT нет: sys._jit.is_available() возвращает False. Откуда брать официальный установщик, показано в инструкции как скачать и установить Python. Отдельная реализация языка, PyPy, работает с JIT давно, и по данным её авторов PyPy 3.12 в среднем примерно в 4 раза быстрее CPython 3.11.

Какие языки компилируемые, а какие интерпретируемые

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

Язык Основная реализация Как исполняется Куда относят
C GCC, clang Машинный код заранее Компилируемый
C++ GCC, clang, MSVC Машинный код заранее Компилируемый
Go go build Машинный код заранее Компилируемый
Rust rustc Машинный код заранее Компилируемый
Swift swiftc Машинный код заранее Компилируемый
Java javac и JVM Байт-код, в JVM интерпретация и JIT Гибрид, чаще называют компилируемым
Kotlin kotlinc и JVM Как у Java Гибрид
C# .NET Промежуточный код IL и JIT Гибрид
Python CPython Байт-код и интерпретатор Интерпретируемый
JavaScript V8, SpiderMonkey Байт-код, интерпретатор и JIT Интерпретируемый
PHP Zend Engine Опкоды и интерпретатор, есть JIT Интерпретируемый
Ruby CRuby Байт-код и интерпретатор, есть JIT Интерпретируемый

Go, например, собирают командой go build, которая, по документации Go, компилирует пакеты вместе с зависимостями. Команда go run компилирует и сразу запускает программу, поэтому снаружи Go похож на скриптовый язык. Где Go применяют, мы рассказывали в статье о языке Go.

JS компилируемый или интерпретируемый

По классическому делению JavaScript интерпретируемый: его распространяют исходным кодом, а исполняет движок браузера или Node.js. По устройству движка он гибрид, потому что V8 сначала строит байт-код, а горячие функции компилирует в машинный код.

C компилируемый или интерпретируемый

C компилируемый. Программу на C собирают компилятором в исполняемый файл под конкретную систему, как в примере выше. Интерпретаторы C существуют, но в работе ими почти не пользуются. С чего начать изучение, показано в статье о языке C для начинающих.

Ответ на школьный тест

В тестах по информатике встречается задание «Выберите один вариант из списка: Python является интерпретируемым языком / компилируемым языком». Правильный ответ: интерпретируемым. Для C, C++, Go и Pascal ответ «компилируемым», для JavaScript, PHP и Ruby: «интерпретируемым».

Ваня БуявецКанал основателя Checkroi Вани БуявцаЗабирайте промпты и обучение по нейросетям в моём Телеграм-каналеБольше 3 800 человек уже применяют Claude Code, ChatGPT и другие нейросети в работе, учёбе, бизнесе и жизниПерейти в канал

Частые заблуждения

  1. «Python ничего не компилирует». Компилирует в байт-код для своей виртуальной машины. Машинных команд процессора при этом не появляется. Файлы .pyc в папке __pycache__ и есть результат этой компиляции.
  2. «Компилируемой программе для запуска ничего не нужно». Программе на Java нужна JVM. Программа на C обычно опирается на системные библиотеки, и собранный на одной ОС файл не запустится на другой.
  3. «Интерпретируемый язык всегда медленный». JavaScript с JIT в нашем замере отстал от C меньше чем вдвое: 0,17 секунды против 0,09.
  4. «Компилируемость задаётся синтаксисом языка». Её задаёт реализация. У Python есть CPython с интерпретатором и PyPy с JIT, интерпретаторы пишут даже для C.
  5. «Компилятор ловит все ошибки». Только те, что видны без запуска. Деление на ноль, если ноль ввёл пользователь, или выход за границы массива компилятор C не поймает.

Что выбрать для первого языка

Рой радостно выбирает первый язык программирования

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

  • Скрипты, анализ данных, боты, нейросети: Python. Почему его советуют для старта, разобрано в статье о языке Python.
  • Сайты и интерфейсы: JavaScript, он работает в каждом браузере.
  • Понять, как устроен компьютер, системное программирование: C.
  • Нагруженный бэкенд: Go или Java.

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

Где освоить Python системно

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

В каталоге собраны курсы по Python от разных школ: сравните программу, длительность и цену.

КурсШколаСтоимость со скидкойВ рассрочкуДлитель­ностьОбзор курса от Checkroi
Профессия «Python-разработчик»
Перейти на сайт курса
SkillboxSkillbox157 335 ₽5987 ₽/мес.10 месяцевОбзор курса
Fullstack-разработчик на Python
Перейти на сайт курса
НетологияНетология137 000 ₽7125 ₽/мес.21 месяцОбзор курса
ДО Профессия Python-разработчик
Перейти на сайт курса
GeekBrainsGeekBrains149 001 ₽3167 ₽/мес.10 месяцевОбзор курса
Автоматизированное тестирование на Python
Перейти на сайт курса
SkillboxSkillbox118 754 ₽4108 ₽/мес.9 месяцевОбзор курса
Профессия Python-разработчик
Перейти на сайт курса
SkillFactorySkillFactory140 040 ₽3890 ₽/мес.10 месяцевОбзор курса

Больше программ — в полном каталоге курсов по Python

Часто задаваемые вопросы

Чем компилируемый язык отличается от интерпретируемого?

Компилируемый язык переводят в машинный код целиком до запуска, на выходе получается исполняемый файл. Интерпретируемый исполняет программа-интерпретатор прямо во время работы, команду за командой, без отдельной сборки.

Python компилируемый или интерпретируемый язык?

Интерпретируемый. Перед исполнением CPython компилирует код в байт-код и кеширует его в файлах .pyc, а исполняет этот байт-код виртуальная машина Python.

JavaScript компилируемый или интерпретируемый?

По классическому делению интерпретируемый: код распространяют исходником, а исполняет его движок браузера или Node.js. Внутри движка V8 работает и интерпретатор, и JIT-компиляторы, которые переводят часто выполняемый код в машинный.

Какие языки программирования компилируемые?

C, C++, Go, Rust и Swift: их программы заранее собирают в машинный код под конкретную систему. Java, Kotlin и C# компилируют в байт-код для виртуальной машины, поэтому их относят к гибридам.

Что быстрее, компилируемый или интерпретируемый язык?

Обычно программы на компилируемых языках работают быстрее. В нашем замере один и тот же цикл на C занял 0,09 секунды, на JavaScript с JIT 0,17, а на Python 3.14 8,4 секунды.

Что такое JIT-компиляция?

Это компиляция во время работы программы: движок переводит в машинный код те участки, которые выполняются чаще всего. JIT есть в V8 для JavaScript, в виртуальной машине Java и в PyPy, а в официальные сборки Python 3.14 для macOS и Windows вошёл экспериментальный JIT.

Читайте Checkroi первым в Google
Добавьте Checkroi в избранные источники — и наши разборы курсов и обзоры школ будут показываться выше в вашей выдаче Google.
Оставить комментарий
0 комментариев
Форма комментария

Оставьте комментарий

Напишите, что думаете. Нам важно ваше мнение!