
По мере того, как экосистема GO продолжает расти, Gopls продолжает масштабироваться
26 июля 2025 г.Ранее этим летом команда Go выпустила версиюv0.12изGopls,языковой серверДля GO, с переписыванием его ядра, которая позволяет ему масштабироваться в более крупных кодовых базах. Это кульминация годичных усилий, и мы рады поделиться нашим прогрессом, а также немного рассказать о новой архитектуре и о том, что это значит для будущего Gopls.
После выпуска V0.12 мы точно настроили новый дизайн, сосредоточившись на создании интерактивных запросов (таких как автоматическое завершение или нахождение ссылок) так же быстро, как и с V0.11, несмотря на то, что они держали гораздо меньше состояния в памяти. Если вы еще этого не сделали, мы надеемся, что вы попробуете:
$ go install golang.org/x/tools/gopls@latest
Мы хотели бы услышать о вашем опыте с ним через этоКраткий обзорПолем
Сокращение использования памяти и время запуска
Прежде чем мы погрузимся в детали, давайте посмотрим на результаты! В таблице ниже показано изменение времени запуска и использования памяти для 28 самых популярных репозиториев GO на GitHub. Эти измерения были проведены после открытия случайно выбранного файла GO и ожидания, пока Gopls полностью загрузит свое состояние, и, поскольку мы предполагаем, что начальная индексация амортизируется во многих сеансах редактирования, мы принимаем эти измерениявторойвремя мы открываем файл.
В этих репо, экономия в среднем около 75%, но снижение памяти не линейно: по мере того, как проекты становятся все больше, то относительное снижение использования памяти. Мы объясним это более подробно ниже.
Gopls и экосистема развивающейся GO
Gopls предоставляет языковые алкогольные редакторы с помощью IDE-подобных функций, таких как автоматическое завершение, форматирование, перекрестные ссылки и рефакторинг. С момента своего начала в 2018 году Gopls консолидировал многие разрозненные инструменты командной строки, такие какгуруВГорано, иGoimportsи сталБэкэнд по умолчанию для расширения VS Code Goа также многие другие редакторы и плагины LSP. Возможно, вы использовали Gopls через своего редактора, даже не зная об этом - это цель!
Пять лет назад Gopls предложил улучшенную производительность, просто поддержав сессию состояния. В то время как более старые инструменты командной строки должны были начинаться с нуля каждый раз, когда они выполняли, Gopls может сэкономить промежуточные результаты, чтобы значительно снизить задержку. Но все это состояние пришло с стоимостью, и со временем мы все чащеслышал от пользователейЭто высокое использование памяти Gopls было едва терпимым.
Между тем, экосистема GO росла, и больше кода было написано в более крупных репозиториях.Go Workspacesпозволил разработчикам работать над несколькими модулями одновременно, иконтейнерное развитиеПоместите языковые серверы во все более ограниченные ресурсы среды. Кодовые базы становились все больше, а среда разработчиков становилась все меньше. Нам нужно было изменить способ масштабирования Gopls, чтобы не отставать.
Пересмотр происхождения компилятора Gopls
Во многих отношениях Gopls напоминает компилятор: он должен читать, анализировать, проверять тип и анализ исходных файлов, для которых он использует многие компиляторастроительные блокипредоставленоGO Стандартная библиотекаиgolang.org/x/toolsмодуль. Эти строительные блоки используют технику «символического программирования»: в работающем компиляторе есть один объект или «символ», который обозначает каждую функцию, такую какfmt.Println
Полем Любая ссылка на функцию представлена как указатель на его символ.
Чтобы проверить, говорят ли две ссылки об одном и том же символе, вам не нужно думать об именах. Вы просто сравниваете указатели. Указатель намного меньше струны, а сравнение указателей очень дешевое, поэтому символы являются эффективным способом представления структуры, такой же сложной, как программа.
Чтобы быстро реагировать на запросы, Gopls v0.11 удерживал все эти символы в памяти, как будто Gopls былСкомпилируйте всю свою программу одновременноПолем Результатом был след памяти, который был пропорционален и намного больше, чем отредактированный исходный код (например, типичные синтаксические деревья обычно в 30 раз больше, чем исходный текст!).
Отдельная компиляция
Дизайнеры первых компиляторов в 1950 -х годах быстро обнаружили пределы монолитной компиляции. Их решение состояло в том, чтобы разбить программу на единицы и компилировать каждую единицу отдельно. Отдельная компиляция позволяет создавать программу, которая не вписывается в память, делая это в мелких кусочках. В ходе подразделения - это пакеты.
Компиляция различных пакетов не может быть полностью разделена: при составлении пакета P компилятор по -прежнему нуждается в информации о том, что предоставляется пакетами, которые импортируют P. Чтобы организовать это, система GO Build составляет все импортированные пакеты P до самого P, и компилятор GO пишет компактную резюме экспортируемого API каждого пакета. Сводки импортированных пакетов P предоставляются в качестве входных данных для компиляции самого P.
Gopls v0.12 приносит отдельную компиляцию в Gopls, повторно используя тот же краткий формат пакета, используемый компилятором. Идея проста, но в деталях есть тонкость. Мы переписываем каждый алгоритм, который ранее проверял структуру данных, представляющую всю программу, так что теперь он работает на одном пакете одновременно и сохраняет результаты для пакета в файлах, как и компилятор, излучающий объектный код.
Например, поиск всех ссылок на функцию, которая использовалась, была такой же простым, как поиск структуры данных программы для всех вхождений определенного значения указателя.
Теперь, когда Gopls обрабатывает каждый пакет, он должен построить и сохранять индекс, который связывает каждое местоположение идентификатора в исходном коде с именем символа, к которому он относится. Во время запроса Gopls загружает и ищет эти индексы. Другие глобальные запросы, такие как «Найти реализации», используют аналогичные методы.
Какgo build
Команда, Gopls теперь используетФайл-кэшХраните для записи резюме информации, рассчитанной из каждого пакета, включая тип каждого объявления, индекс перекрестных ссылок и набор методов каждого типа. Поскольку кэш сохраняется в разных процессах, вы заметите, что во второй раз, когда вы начинаете Gopls в своем рабочем пространстве, он становится готовым служить гораздо быстрее, и если вы запустите два экземпляра Gopls, они работают вместе синергетически.
Результатом этого изменения является то, что использование памяти Gopls пропорционально количеству открытых пакетов и их прямого импорта. Вот почему мы наблюдаем подсознательное масштабирование в диаграмме выше: по мере того, как репозитории становятся все больше, доля проекта, наблюдаемая каким -либо одним открытым пакетом, становится меньше.
Мелкозернистая недействительность
Когда вы вносите изменения в одном пакете, необходимо только перекомпилировать пакеты, которые импортируют один, прямо или косвенно. Эта идея является основой всех инкрементных систем сборки с момента создания в 1970 -х годах, и Gopls использует ее с момента ее создания. По сути, каждый клавиш в вашем редакторе с поддержкой LSP начинает постепенную сборку! Однако в крупном проекте косвенные зависимости складываются, что делает эти постепенные восстановления слишком медленными. Оказывается, что большая часть этой работы не является строго необходимой, потому что большинство изменений, такие как добавление оператора в существующей функции, не влияют на резюме импорта.
Если вы внесете небольшое изменение в одном файле, мы должны перекомпилировать его пакет, но если изменение не влияет на резюме импорта, нам не нужно компилировать какие -либо другие пакеты. Эффект изменения - «обрезка». Изменение, которое влияет на резюме импорта, требует отмены пакетов, которые непосредственно импортируют этот пакет, но большинство таких изменений не повлияют на резюме импортатеПакеты, в этом случае эффект все еще обрезан и избегает перекомпилирования косвенных импортеров.
Благодаря этой обрезке редко изменение в пакете низкого уровня требуется перекомпилированиевсепакеты, которые косвенно зависят от этого пакета. Обрезка инкрементных перестройков делает объем работы, пропорционально объему каждого изменения. Это не новая идея: она была введенаВестаа также использовался вgo build
Полем
Выпуск V0.12 вводит аналогичную методику обрезки для Gopls, и продвигаясь на шаг вперед для реализации более быстрой эвристики обрезки на основе синтаксического анализа. Сохраняя упрощенный график ссылок на символы в памяти, GOPLS может быстро определить, изменение в упаковкеc
может повлиять на пакетa
через цепочку ссылок.
В примере выше, нет цепочки ссылок изa
кc
Таким образом, A не подвергается воздействию изменений в C, даже если он косвенно зависит от этого.
Новые возможности
Несмотря на то, что мы довольны улучшением производительности, которые мы достигли, мы также рады нескольким функциям Gopls, которые возможны сейчас, когда Gopls больше не ограничивается памятью.
Первый - надежный статический анализ. Ранее наш драйвер статического анализа должен был работать на представлении Gopls в памяти пакетов, поэтому он не мог проанализировать зависимости: это привлечет слишком много дополнительного кода. При удалении этого требования мы смогли включить новый драйвер для анализа в Gopls v0.12, который анализирует все зависимости, что приводит к большей точности.
Например, Gopls теперь сообщает о диагностике дляPrintf
форматирование ошибок даже в ваших пользовательских обертках вокругfmt.Printf
Полем Примечательно,go vet
обеспечивал этот уровень точности в течение многих лет, но Gopls не смог сделать это в режиме реального времени после каждого редактирования. Теперь это может.
Второеболее простая конфигурация рабочей областииУлучшенная обработка для битов сборкиПолем Эти две функции обозначают Gopls, «поступающие правильные вещи», когда вы открываете любой файл GO на вашей машине, но оба были невозможны без работы оптимизации, потому что (например) каждая конфигурация сборки умножает следов памяти!
Попробуйте!
В дополнение к масштабируемости и улучшениям производительности, мы также исправленымногочисленныесообщили об ошибкахи много не сообщаемых, которые мы обнаружили при улучшении тестового охвата во время перехода.
Чтобы установить новейшие Gopls:
$ go install golang.org/x/tools/gopls@latest
Пожалуйста, попробуйте и заполнитеопрос- и если вы столкнетесь с ошибкой,сообщить об этомИ мы исправим это.
Роберт Финдли и Алан Донован
ФотоЭмма ХендерсоннаНеспособный
Эта статья доступна на
Оригинал