Go давно умеет быть «достаточно быстрым», но начиная с 1.20 у нас появляется новая игрушка, которая позволяет выжать из железа ещё пару‑тройку процентов без переписывания кода — профилируемая оптимизация, она же PGO.
Команда Go добавила PGO в 1.20 как превью: это уже работает, даёт примерно 2–4% экономии CPU на типичных нагрузках, но официально предупреждают, что фича ещё с шероховатостями и в прод по��а включать стоит аккуратно.
Если совсем по‑простому, PGO — это когда компилятор сначала смотрит, как ваш сервис реально живёт под нагрузкой, а потом на основе этих данных пересобирает бинарник так, чтобы самые горячие куски кода бегали быстрее.
Без профиля компилятор «угадывает» горячие пути по статике, с профилем — получает реальную статистику по функциям, веткам и вызовам, и может перестать гадать.
Пайплайн PGO по‑человечески
Снаружи PGO выглядит удивительно незаморочено, особенно для Go.
Сначала вы собираете обычный бинарник: go build, как делали всегда, без всяких флагов.
Гоняете этот бинарник под типичной нагрузкой и снимаете CPU‑профиль через pprof (бенчи, нагрузочные тесты, кусок продакшена — что есть).
Получившийся cpu.pprof скармливаете компилятору: go build -pgo=cpu.pprof.
На выходе получаете «такой же, но побыстрее» бинарник, который делает то же самое, но тратит меньше CPU, потому что компилятор оптимизировал реально горячие места.
В Go 1.20 PGO в основном управляет инлайнингом: компилятор лучше понимает, какие функции есть смысл развернуть внутрь вызовов, а какие трогать не нужно.
Команда прямо пишет, что это только первый шаг: профили «несут много информации», а 1.20 пока «лишь слегка царапает поверхность» и использует её только для части оптимизаций.
Что даёт PGO в реальных цифрах
В официальном блоге по 1.20 честно показывают, что типичные программы с включённым PGO выигрывают около 2–4% по CPU.
Это не история «минус 50% времени ответа», а такая тихая утилитарная магия: вы просто собираете бинарник с профилем и получаете пару процентов, которые сами по себе небольшие, но на паре сотен инстансов внезапно превращаются в ощутимую экономию.
Когда позже, уже на 1.21, команда выкатывает полноценную статью про PGO, там фигурируют цифры 2–7% выигрыша на разных нагрузках, потому что к инлайнингу добавили ещё и де‑виртуализацию интерфейсных вызовов.
Но уже сейчас, в 2023‑м, из превью 1.20 видно главное: PGO для Go — это не эксперимент энтузиастов, а серьёзный долгосрочный вектор, в который команда явно вкладывается.
Почему это важно именно для Go
Go исторически позиционируется как язык инфраструктуры: на нём пишут прокси, балансировщики, бекенды, всякий CNCF‑зоопарк, который живёт в проде под постоянной нагрузкой.
В таких сценариях «ещё 3%» — это не просто красивый график в бенчмарке, а реальные деньги и меньше боли для SRE: либо та же нагрузка на меньшем железе, либо больший запас по пикам.
При этом Go не хочет превращаться в «язык для супер‑оптимизаторов», где ты живёшь в флагах компилятора; философия наоборот — сделать PGO так, чтобы обычный разработчик мог включить его одной строчкой в CI и забыть.
Отсюда понятный интерфейс -pgo=profile.pprof и ставка на стандартные инструменты профилирования (pprof и компания), без экзотики.
А что дальше: немного «пророчеств»
Сейчас, летом 2023‑го, у нас есть превью PGO в 1.20 и уже анонсируется, что в 1.21 эта штука станет полноценной фичей с более широким набором оптимизаций.
Команда прямо обещает: будущие релизы будут «ещё лучше использовать профили», то есть PGO будет только наращивать влияние на производительность.
Возможна, что эволюция пойдёт в несколько сторон:
Больше оптимизаций поверх профиля
В 1.20 профили в основном управляют инлайнингом, в 1.21 добавляют де‑виртуализацию интерфейсных вызовов, а дальше логично ждать оптимизаций в области раскладки кода, работы с памятью и ветвлений.
Интеграция с continuous profiling
Крупные компании уже собирают профили с продакшена постоянно, и напрашивается сценарий, когда свежий профиль регулярно летит в CI, а новый релиз сервиса автоматически пересобирается с актуальным PGO.
Упрощение жизни обычным командам.
Пока PGO — это всё ещё «игрушка для тех, кому не лень настроить профили», но документация и блоги явно толкают экосистему к появлению готовых шаблонов и тулов, где «включить PGO» будет примерно так же просто, как сейчас включить тесты или линтер.
Разные профили под разные типы нагрузок
Уже сегодня оговаривается, что PGO максимально полезен, если профиль соответствует реальной боевой нагрузке, а не синтетике. Логичный следующий шаг — несколько профилей и несколько сборок: один бинарник, оптимизированный под batch, другой — под онлайн‑трафик, третий — под эксперименты.
Стоит ли заморачиваться прямо сейчас
Если у вас небольшой сервис на десятке инстансов, а CPU не горит, PGO в 2023‑м — скорее приятный эксперимент, чем must have. Но если вы крутите тяжёлый Go‑трафик и уже умеете снимать профили из продакшена, то превью PGO в 1.20 — это шанс бесплатно забрать несколько процентов производительности, пока остальные только обсуждают generics.
Самое интересное, что инвестиция здесь не в переписывание кода, а в инфраструктуру: один раз встроить профили в пайплайн и научиться периодически обновлять PGO‑профиль.
А дальше компилятор будет становиться умнее от релиза к релизу, и каждый новый go build -pgo=... будет выжимать из вашего старого кода всё больше — вы только успевайте обновлять версию Go.
