G/M/P и GOMAXPROCS
«Полку» переехала в контейнер с квотой на CPU, и параллелизм там оказался совсем не таким, как на ноутбуке Миши. Сергей объяснил, откуда в контейнере берётся лимит параллелизма.
планировщик оперирует тройкой G/M/P: G — горутина, M — поток ОС, P — контекст с очередью горутин; параллелизм ограничен числом P, которое задаёт GOMAXPROCS.
Три буквы
- G (goroutine) — сама горутина: стек, состояние, инструкция для продолжения. Десятки тысяч G.
- M (machine) — поток операционной системы, на котором исполняется Go-код. M немного — по числу ядер плюс запас, не считая потоков, ушедших в блокирующие syscall'ы.
- P (processor) — контекст исполнения: держит очередь готовых горутин. P столько, сколько позволяет
GOMAXPROCS.
M не работает без P: чтобы исполнять Go-код, потоку нужен контекст с очередью.
GOMAXPROCS
По умолчанию GOMAXPROCS равен числу доступных процессоров, а с Go 1.25 дополнительно ограничивается контейнерным CPU-лимитом (cgroup), если он задан. Именно P определяет, сколько горутин исполняется параллельно — одновременно на разных ядрах. Горутин может быть сто тысяч, но параллельно крутятся не больше числа P; остальные ждут в очередях.
fmt.Println(runtime.GOMAXPROCS(0)) // текущее число P
Цикл исполнения
Каждый P держит локальную очередь готовых G. M захватывает P, берёт G из очереди и исполняет. Когда G блокируется — например, читает из пустого канала — планировщик паркует её, а M берёт из очереди следующую. Горутина, которая «ждёт», не занимает ни M, ни P: её место занимает другая.
Вы узнаете:
- зачем планировщику локальные очереди P и глобальная
- как настроить
GOMAXPROCSв контейнерах
Проверьте себя
Что такое G в модели G/M/P планировщика?
Заблокированная на канале горутина продолжает занимать свой поток M?
8 тяжёлых задач на 4 P (GOMAXPROCS=4). Во сколько раз это дольше 4 таких же задач?
правильных ответов
G — горутина, M — поток, P — контекст с очередью. Параллелизм = число P = GOMAXPROCS. Заблокированная G не держит поток.
10 000 ₽ · 60 минут · онлайн