> Сколько потоков запускается в runtime приложении Go по умолчанию (Go)

Уровень: middle · Роль: backend · Категория: Технические вопросы

Компании: Фабрика решений

Стек: Go

> Пример ответа

Короткий ответ

В runtime приложения Go по умолчанию запускается один поток операционной системы (M), на котором работает goroutine main. Однако runtime также создаёт вспомогательные системные потоки для сборщика мусора, обработки сигналов и других внутренних задач. Точное количество потоков зависит от версии Go и настроек, но пользовательский код выполняется на одном потоке, пока не будут созданы дополнительные goroutine или не изменится GOMAXPROCS.

Подробное объяснение

В Go используется модель планировщика M:N, где M - поток ОС, P - логический процессор, G - goroutine. По умолчанию GOMAXPROCS равен количеству ядер CPU на машине, но это не значит, что сразу запускается столько потоков. Runtime создаёт потоки лениво - только когда есть работающие goroutine, которые не могут быть выполнены на существующих M.

Изначально создаётся один M для main goroutine. Дополнительные M появляются при блокировке (например, syscall или channel) или при увеличении параллелизма. Также runtime всегда запускает несколько служебных потоков: sysmon (мониторинг), forcegc (принудительный GC), и потоки для обработки сигналов (signal thread). Их количество может варьироваться, но обычно это 2-4 потока.

Важно понимать: GOMAXPROCS ограничивает число параллельно выполняющихся goroutine, но не число потоков ОС. Потоков может быть больше, если goroutine блокируются на системных вызовах - для каждого такого вызова может создаваться отдельный M.

На практике

На практике разработчику редко нужно знать точное количество потоков. Достаточно понимать, что:

  • GOMAXPROCS по умолчанию = число ядер, но это не число потоков.
  • Потоки создаются динамически и переиспользуются.
  • Служебные потоки runtime не влияют на производительность приложения.
  • Если нужно ограничить параллелизм, используйте GOMAXPROCS или семафоры, а не попытки управлять потоками напрямую.

Пример кода

GO
package main
import (
"fmt"
"runtime"
)
func main() {
fmt.Println("GOMAXPROCS:", runtime.GOMAXPROCS(0))
fmt.Println("NumCPU:", runtime.NumCPU())
// Точное число потоков ОС можно получить только через системные утилиты
// или cgo, в чистом Go такой API нет.
}

Как отвечать на собеседовании

Начните с главного: один поток для main goroutine, плюс служебные потоки runtime. Затем поясните связь с GOMAXPROCS и моделью M:N. Упомяните, что потоки создаются лениво и переиспользуются. Если спросят про точное число - скажите, что оно не фиксировано и зависит от версии Go и нагрузки. Хорошо показать понимание разницы между M, P и G.

Что проверяет интервьюер

Интервьюер проверяет:

  • Понимание модели планировщика Go (M, P, G).
  • Знание GOMAXPROCS и его отличия от числа потоков.
  • Понимание ленивого создания потоков и переиспользования M.
  • Осведомлённость о служебных потоках runtime (sysmon, GC, signal).

Типичные ошибки

  • Утверждение, что потоков столько же, сколько ядер - это неверно, GOMAXPROCS не равен числу потоков.
  • Игнорирование служебных потоков runtime.
  • Путаница между goroutine и потоком ОС.
  • Утверждение, что количество потоков фиксировано - оно динамическое.
  • Непонимание, что блокирующий syscall может создать дополнительный поток.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью