Как устроена многозадачность в Go и какой механизм планирования используется
Что проверяют
Знаете ли вы, что происходит под go f(): как тысячи горутин укладываются на несколько потоков ОС и что будет при блокировке. Слов «легковесный поток» мало, ждут модель GMP. Следом спрашивают про вытеснение и про GOMAXPROCS в контейнере.
Как отвечать
Go реализует модель M:N: много горутин выполняются на небольшом числе потоков ОС, и распределяет их планировщик рантайма, а не ядро.
- G: горутина, стек стартует с 2 КБ и растёт по мере нужды;
- M: поток ОС, который исполняет код;
- P: логический процессор, контекст планирования. Число P равно
GOMAXPROCS, по умолчанию это число доступных CPU. Горутину выполняет только M, взявший P.
У каждого P есть локальная очередь готовых горутин, плюс общая глобальная. Если своя очередь пуста, P крадёт половину чужой (work stealing) и периодически заглядывает в глобальную, чтобы там никто не голодал.
Блокировки разного рода обрабатываются по-разному. На канале или мьютексе горутина паркуется, а M сразу берёт следующую. Сетевой ввод-вывод идёт через netpoller (epoll, kqueue), поэтому поток не простаивает. Блокирующий системный вызов уводит M вместе с горутиной, а P передаётся другому потоку.
Вытеснение: с Go 1.14 оно асинхронное, через сигналы, поэтому горутина с тесным циклом без вызовов функций больше не вешает планировщик. Фоновый sysmon снимает горутины, которые работают дольше примерно 10 мс.
Про контейнеры: начиная с Go 1.25 GOMAXPROCS по умолчанию учитывает CPU-лимит cgroup, раньше для этого ставили go.uber.org/automaxprocs.
Где спотыкаются
Путают конкурентность и параллелизм. При GOMAXPROCS=1 горутин может быть сколько угодно, но Go-код в каждый момент выполняет один поток.
Думают, что GOMAXPROCS ограничивает число потоков. Он ограничивает только одновременно исполняющие Go-код, а потоки, заблокированные в системных вызовах, создаются сверх него.
Считают горутины бесплатными и не думают об утечках: горутина, навсегда застрявшая на чтении из канала, живёт до конца процесса. Её ловят через pprof по профилю goroutine или goleak в тестах.