Планировщик Go использует многопоточную модель M:N, где M goroutine отображаются на N потоков ОС. Работа планировщика основана на модели GMP (Goroutine, Machine, P).
- G (Goroutine): Легковесный поток выполнения. Создаётся по ключевому слову
go
.
- M (Machine): Поток ОС. Выполняет код goroutine. Горячий поток, блокирующие системные вызовы выполняются на отдельном M.
- P (Processor): Локальная очередь goroutine, к которой привязан M. Количество P по умолчанию равно числу логических ядер CPU и контролируется переменной
GOMAXPROCS
.
Принцип работы:
- Когда нужно запустить goroutine, она помещается в локальную очередь P.
- M, привязанный к P, берёт goroutine из очереди и начинает её выполнение.
- Если локальная очередь P пуста, M может "украсть" goroutine из очереди другого P.
- Если goroutine блокируется (например, при системном вызове), текущий M отвязывается от P, а P привязывается к другому доступному M или создается новый M. Блокированная goroutine остаётся на заблокированном M до завершения блокирующей операции.
- Когда блокирующая операция завершается, goroutine возвращается в очередь другого P или текущего P, если он свободен.
- Планировщик периодически (каждые 10 мс) проверяет goroutine на выполнение более 10 мс для принудительного переключения (preemption).
Преимущества такого подхода: