Назад к вопросам
Principal
221
questionbank

Какие сущности присутствуют в планировщике?

Sobes Copilot

Получайте ответы в реальном времени

Ответ от нейросети

sobes.tech AI

В планировщике Golang (M) присутствуют следующие сущности:

  • M (Machine): Представляет собой поток операционной системы. Отвечает за исполнение G-кода на процессоре. M забирает G из локальной очереди P или обходной очереди.
  • P (Processor): Логический процессор (контекст). Содержит локальную очередь готовых к выполнению G. P привязан к M, и только один M может быть привязан к P в любой момент времени. Количество P по умолчанию равно GOMAXPROCS.
  • G (Goroutine): Легковесный поток выполнения. Представляет собой конкурентную функцию или метод. G исполняется на P.
// Представление горутины, содержит стэк, указатель на функцию и состояние.
type g struct {
	stack       stack     // stask описывает стек горутины
	stackguard  uintptr   // для проверки стэка
	stackbase   uintptr   // база стэка
	sched stato     // для планировщика
    // ... другие поля
}
// Представление логического процессора, имеет свою локальную очередь горутин
type p struct {
	id          int    // ID логического процессора
	runq        []*g   // локальная очередь горутин
	// ... другие поля
}
// Представление потока ОС, исполняет горутины с помощью p
type m struct {
	g0      *g    // горутина для планировщика
	curg    *g    // текущая горутина
	p       *p    // привязанный логический процессор
    // ... другие поля
}

Взаимодействие между сущностями следующее:

  1. Горутины (G) помещаются в локальные очереди логических процессоров (P).
  2. Потоки ОС (M) берут P и из их локальных очередей забирают G для выполнения на процессоре.
  3. Если локальная очередь P пуста, M может попытаться украсть G из локальной очереди другого P (work-stealing).
  4. При блокирующих системных вызовах, M отвязывается от P, и другой M может занять этот P для выполнения других G. Заблокированный G остается привязанным к отвязавшемуся M.
// Упрощенная иллюстрация планирования:
// m0 ---(привязан к)---> p0 ---> [g1, g2, g3] (локальная очередь)
// m1 ---(привязан к)---> p1 ---> [g4, g5]
// m2 (свободен) ---> ищет p0 или p1 для steal

Таким образом, планировщик Golang эффективно использует доступные ядра процессора, распределяя выполнение легковесных горутин между потоками ОС через логические процессоры.