Я гуглил и ковырялся на сайте Go, но, похоже, не могу найти объяснения необыкновенному времени сборки Go. Являются ли они продуктами языковых возможностей (или их отсутствием), высоко оптимизированным компилятором или чем-то еще? Я не пытаюсь продвигать Go; Мне просто любопытно.
performance
compiler-construction
build-process
go
Эван Кроске
источник
источник
Ответы:
Анализ зависимостей.
Go FAQ используется , чтобы содержать следующую фразу:
Хотя этой фразы больше нет в FAQ, эта тема более подробно обсуждается в докладе Go на Google , в котором сравнивается подход к анализу зависимостей в C / C ++ и Go.
Это главная причина быстрой компиляции. И это по замыслу.
источник
Я думаю, дело не в том, что компиляторы Go работают быстро , а в том, что другие компиляторы работают медленно .
Компиляторы C и C ++ должны анализировать огромное количество заголовков - например, компиляция C ++ «hello world» требует компиляции 18 тыс. Строк кода, что составляет почти половину мегабайта источников!
Компиляторы Java и C # работают в виртуальной машине, а это означает, что прежде чем они смогут что-либо скомпилировать, операционная система должна загрузить всю виртуальную машину, затем они должны быть JIT-скомпилированы из байт-кода в собственный код, и все это занимает некоторое время.
Скорость компиляции зависит от нескольких факторов.
Некоторые языки предназначены для быстрой компиляции. Например, Pascal был разработан для компиляции с использованием однопроходного компилятора.
Компиляторы тоже могут быть оптимизированы. Например, компилятор Turbo Pascal был написан на оптимизированном вручную ассемблере, что в сочетании с языковым дизайном привело к действительно быстрому компилятору, работающему на оборудовании класса 286. Я думаю, что даже сейчас современные компиляторы Pascal (например, FreePascal) работают быстрее, чем компиляторы Go.
источник
Есть несколько причин, почему компилятор Go намного быстрее, чем большинство компиляторов C / C ++:
Основная причина : большинство компиляторов C / C ++ демонстрируют исключительно плохие дизайны (с точки зрения скорости компиляции). Кроме того, с точки зрения скорости компиляции, некоторые части экосистемы C / C ++ (такие как редакторы, в которых программисты пишут свои коды) не разработаны с учетом скорости компиляции.
Основная причина : быстрая скорость компиляции была осознанным выбором в компиляторе Go, а также в языке Go
Компилятор Go имеет более простой оптимизатор, чем компиляторы C / C ++
В отличие от C ++, Go не имеет шаблонов и встроенных функций. Это означает, что Go не нужно выполнять какой-либо шаблон или функцию создания экземпляра.
Компилятор Go генерирует низкоуровневый код сборки быстрее, и оптимизатор работает с кодом сборки, в то время как в типичном компиляторе C / C ++ оптимизация пропускает работу над внутренним представлением исходного исходного кода. Дополнительные издержки в компиляторе C / C ++ обусловлены тем фактом, что необходимо создать внутреннее представление.
Окончательное связывание (5l / 6l / 8l) программы Go может быть медленнее, чем связывание программы C / C ++, потому что компилятор Go просматривает весь использованный код сборки и, возможно, также выполняет другие дополнительные действия, которые выполняет C / C ++. линкеры не делают
Некоторые компиляторы C / C ++ (GCC) генерируют инструкции в текстовом виде (для передачи ассемблеру), в то время как компилятор Go генерирует инструкции в двоичном виде. Необходимо выполнить дополнительную работу (но не так много), чтобы преобразовать текст в двоичный файл.
Компилятор Go предназначен только для небольшого числа архитектур ЦП, в то время как компилятор GCC предназначен для большого количества ЦП.
Компиляторы, которые были разработаны с целью обеспечения высокой скорости компиляции, такие как Jikes, работают быстро. На процессоре с тактовой частотой 2 ГГц Jikes может компилировать более 20000 строк Java-кода в секунду (а инкрементный режим компиляции еще более эффективен).
источник
Эффективность компиляции была главной целью проекта:
Часто задаваемые вопросы по языку довольно интересны в отношении специфических языковых особенностей, связанных с синтаксическим анализом:
источник
aType
оно было ссылкой на переменную, и позже на этапе семантического анализа, когда вы обнаружите, что это не вы печатаете значимую ошибку в то время.Хотя большинство из вышесказанного является верным, есть один очень важный момент, который не был упомянут в действительности: управление зависимостями.
Go нужно только включить пакеты, которые вы импортируете напрямую (как те, которые уже импортированы, что им нужно). Это резко контрастирует с C / C ++, где каждый отдельный файл начинается с заголовков x, которые включают y заголовков и т. Д. Итог: Компиляция Go занимает линейное время по отношению к количеству импортируемых пакетов, где C / C ++ занимает экспоненциальное время.
источник
Хорошим тестом для эффективности перевода компилятора является самокомпиляция: сколько времени требуется компилятору для компиляции? Для C ++ это занимает очень много времени (часов?). Для сравнения, компилятор Pascal / Modula-2 / Oberon скомпилирует себя менее чем за один секунду на современной машине [1].
Go был вдохновлен этими языками, но некоторые из основных причин такой эффективности:
Четко определенный синтаксис, который математически обоснован, для эффективного сканирования и анализа.
Безопасный по типу и статически скомпилированный язык, который использует отдельную компиляцию с проверкой зависимостей и типов через границы модуля, чтобы избежать ненужного повторного чтения файлов заголовков и повторной компиляции других модулей - в отличие от независимой компиляции, как в C / C ++, где никакие такие межмодульные проверки не выполняются компилятором (отсюда необходимость перечитывать все эти заголовочные файлы снова и снова, даже для простой однострочной программы "hello world").
Эффективная реализация компилятора (например, однопроходный синтаксический анализ с рекурсивным спуском сверху вниз), чему, конечно, очень помогают пункты 1 и 2 выше.
Эти принципы уже были известны и в полной мере реализованы в 1970-х и 1980-х годах на таких языках, как Mesa, Ada, Modula-2 / Oberon и некоторых других, и только сейчас (в 2010-х) нашли свое отражение в современных языках, таких как Go (Google). , Swift (Apple), C # (Microsoft) и ряд других.
Будем надеяться, что это скоро станет нормой, а не исключением. Чтобы попасть туда, должны произойти две вещи:
Во-первых, поставщики программных платформ, такие как Google, Microsoft и Apple, должны начать с поощрения разработчиков приложений использовать новую методологию компиляции, позволяя им повторно использовать существующую кодовую базу. Это то, что Apple сейчас пытается сделать с языком программирования Swift, который может сосуществовать с Objective-C (поскольку он использует ту же среду выполнения).
Во-вторых, сами базовые программные платформы должны со временем переписываться с использованием этих принципов, одновременно изменяя иерархию модулей в процессе, чтобы сделать их менее монолитными. Это, конечно, гигантская задача, которая может занять большую часть десятилетия (если они достаточно смелы, чтобы на самом деле это сделать - в чем я не уверен в случае с Google).
В любом случае, именно платформа стимулирует принятие языка, а не наоборот.
Ссылки:
[1] http://www.inf.ethz.ch/personal/wirth/ProjectOberon/PO.System.pdf , стр. 6: «Компилятор компилируется примерно за 3 секунды». Эта цитата предназначена для недорогой платы разработки Xilinx Spartan-3 FPGA, работающей на тактовой частоте 25 МГц и имеющей 1 МБайт основной памяти. Исходя из этого, легко экстраполировать до «менее 1 секунды» для современного процессора, работающего на тактовой частоте значительно выше 1 ГГц, и нескольких гигабайт основной памяти (т.е. на несколько порядков более мощных, чем плата FPGA Xilinx Spartan-3), даже с учетом скоростей ввода / вывода. Уже в 1990 году, когда Oberon работал на 25-МГц процессоре NS32X32 с 2-4 МБ основной памяти, компилятор скомпилировал себя всего за несколько секунд. Понятие фактического ожиданиячтобы компилятор заканчивал цикл компиляции, он был совершенно неизвестен программистам Oberon даже тогда. Для типичных программ всегда требовалось больше времени, чтобы убрать палец с кнопки мыши, которая вызвала команду компиляции, чем ждать, пока компилятор завершит компиляцию, только что запущенную. Это было действительно мгновенное удовлетворение с почти нулевым временем ожидания. И качество создаваемого кода, хотя и не всегда полностью на уровне лучших на тот момент компиляторов, было удивительно хорошим для большинства задач и в целом вполне приемлемым.
источник
Go был разработан, чтобы быть быстрым, и это показывает.
Обратите внимание, что GO - не единственный язык с такими возможностями (модули являются нормой в современных языках), но они справились хорошо.
источник
Цитата из книги « Язык программирования Go » Алана Донована и Брайана Кернигана:
источник
Основная идея компиляции на самом деле очень проста. Парсер рекурсивного спуска, в принципе, может работать со скоростью, связанной с вводом / выводом. Генерация кода в основном очень простой процесс. Таблица символов и система базовых типов не требуют больших вычислений.
Тем не менее, нетрудно замедлить работу компилятора.
Если есть фаза препроцессора, с многоуровневыми включающими директивами, определениями макросов и условной компиляцией, какими бы полезными они ни были, загрузить их несложно. (Например, я имею в виду заголовочные файлы Windows и MFC.) Именно поэтому необходимы предварительно скомпилированные заголовки.
С точки зрения оптимизации сгенерированного кода, нет предела тому, сколько обработки может быть добавлено к этой фазе.
источник
Просто (по моим собственным словам), потому что синтаксис очень прост (анализировать и анализировать)
Например, нет наследования типов означает, не проблемный анализ, чтобы выяснить, соответствует ли новый тип правилам, наложенным базовым типом.
Например, в этом примере кода: «интерфейсы» компилятор не проверяет, реализует ли заданный тип данный интерфейс при анализе этого типа. Только до тех пор, пока он не будет использован (и ЕСЛИ он используется), проверка выполняется.
В другом примере компилятор сообщает вам, если вы объявляете переменную и не используете ее (или если вы должны хранить возвращаемое значение, а вы нет)
Следующее не компилируется:
Этот вид принудительных мер и принципов делает полученный код более безопасным, и компилятору не нужно выполнять дополнительные проверки, которые может сделать программист.
В целом все эти детали упрощают анализ языка, что приводит к быстрой компиляции.
Опять же своими словами.
источник
Я думаю, что Go был разработан параллельно с созданием компилятора, поэтому они были лучшими друзьями с рождения. (ИМО)
источник
Что еще?
источник