Go: Планировщик (GMP)

11 вопросов

1 Что такое модель GMP?

Модель планировщика Go: G (goroutine) - горутина, M (machine) - поток ОС, P (processor) - контекст выполнения, связка с очередью горутин. M выполняет G на P; P привязан к M. Несколько G могут стоять в очереди на P; количество P обычно равно GOMAXPROCS.

Открыть отдельно →
2 Что означают G, M и P?

G - горутина (структура g): стек, функция, состояние. M - поток ОС (thread), выполняет код Go. P - логический процессор (структура p): очередь локальных горутин, кеш и т.д. У каждого P может быть свой M; M без P не выполняет пользовательский код.

Открыть отдельно →
3 Какие очереди есть в планировщике?

У каждого P - локальная очередь горутин (runqueue). Есть глобальная очередь (редко используется при нормальной загрузке). При нехватке работы P забирает половину горутин у другого P (work stealing). Новые горутины обычно попадают в локальную очередь P создателя.

Открыть отдельно →
4 Что такое work stealing?

Когда у P пустая локальная очередь, он пытается "украсть" половину горутин из очереди другого P или взять из глобальной очереди. Балансирует нагрузку между ядрами без центральной очереди. Уменьшает простаивание P.

Открыть отдельно →
5 Что такое Network Poller?

Компонент рантайма: интегрирует с сетевым I/O (epoll, kqueue, IOCP). Когда горутина блокируется на сетевой операции, она снимается с M и не занимает поток; при готовности события поллер будит горутину и ставит в очередь. Потоки не блокируются на сети.

Открыть отдельно →
6 Что такое spinning M?

M в режиме "крутится" (spinning), когда ищет готовую к выполнению горутину вместо того, чтобы уходить в сон. Небольшое число spinning M ускоряет реакцию на появление новых горутин. Слишком много spinning - лишняя нагрузка на CPU.

Открыть отдельно →
7 Что такое handoff в планировщике?

Когда горутина блокируется (например, на канале или системном вызове), P может передать (hand off) другую горутину из своей очереди на тот же M или освободить P для другого M. Handoff - передача работы между M и P при блокировках.

Открыть отдельно →
8 Что такое preemption (вытеснение) в Go 1.14+?

С Go 1.14 планировщик вытесняет долго выполняющиеся горутины без точек вызова (tight loop), чтобы другие горутины получили время. Раньше кооперативная многозадачность могла оставлять одну горутину надолго на P. Preemption основан на асинхронных сигналах и проверках в точках вызова.

Открыть отдельно →
9 Что даёт GODEBUG=schedtrace?

Периодический вывод в stderr: количество горутин, потоков (M), процессоров (P), состояние планировщика. Помогает увидеть рост числа горутин, простаивание P и общую картину. Для детального разбора используют scheddetail вместе с schedtrace.

GODEBUG=schedtrace=1000 ./app
Открыть отдельно →
10 Что делают runtime.Gosched и LockOSThread?

runtime.Gosched() - добровольно отдать текущий квант времени: текущая горутина уходит в очередь, планировщик выбирает другую. runtime.LockOSThread() привязывает горутину к текущему потоку ОС до UnlockOSThread; нужен для C-библиотек, требующих один поток, или для низкоуровневых задач.

runtime.Gosched()
runtime.LockOSThread()
defer runtime.UnlockOSThread()
Открыть отдельно →
11 Почему M может быть больше, чем P?

M создаются при блокировке в системном вызове (syscall): текущий M блокируется, рантайм может создать новый M для привязки к освободившемуся P и продолжения выполнения горутин. После возврата из syscall старый M может вернуться в пул. Поэтому число M не ограничено числом P.

Открыть отдельно →
🧠Квиз 🏆Лидеры 🎯Собесед. 📖Вопросы 📚База зн.