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.