← Назад к вопросам

Сколько есть очередей в модели GMP?

3.0 Senior🔥 191 комментариев
#Конкурентность и горутины

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Очереди в модели GMP Go: иерархия и их назначение

В модели планирования GMP (Goroutine, Machine, Processor) языка Go используется не одна, а несколько типов очередей, организованных иерархически для эффективного распределения горутин. Их можно разделить на глобальные (общепроцессорные), локальные (per-P) и специальные. Подробный размотр:

1. Локальные очереди (Local Runqueues) — P.runq

Каждый логический процессор (P) имеет собственную локальную очередь фиксированного размера (обычно 256 элементов) в виде кольцевого буфера (runq [256]guintptr). В неё планировщик помещает новые горутины, созданные в контексте данного P.

// Упрощённая структура P (логического процессора)
type p struct {
    // Локальная очередь (кольцевой буфер)
    runq    [256]guintptr
    runqhead uint32
    runqtail uint32
    ...
}

Назначение:

  • Быстрое добавление/извлечение горутин без блокировок (только операции с атомарными счетчиками head и tail).
  • Кэширование горутин "близко" к потоку ОС (M), который их исполняет, что повышает локальность данных.
  • Приоритизация: планировщик сначала проверяет локальную очередь, затем глобальную.

2. Глобальная очередь (Global Runqueue) — sched.runq

Одна на весь процесс Go, представлена в структуре schedt (runtime.sched.runq). Это связанный список горутин, доступ к которому защищен глобальной мьютексой (sched.lock).

type schedt struct {
    runq     gQueue // Глобальная очередь (связанный список)
    runqsize int32
    lock     mutex
    ...
}

Назначение:

  • Балансировка нагрузки: когда локальная очередь P переполнена, половина её горутин (runq/2) перемещается в глобальную очередь (runtime.runqputglobal).
  • Прием горутин от других P в рамках work-stealing (воровства задач) — если у P пустая локальная очередь, он забирает часть горутин из глобальной.
  • Хранение горутин, которые не привязаны к конкретному P (например, разбуженные из сети/таймера).

3. Очередь воровства (Work-stealing Queue)

Не отдельная структура данных, а алгоритм доступа к очередям других P. Когда у P пустая локальная очередь и глобальная, он случайно выбирает другой P и "ворует" половину горутин из его локальной очереди (runtime.runqsteal).

Назначение:

  • Динамическая балансировка нагрузки между процессорами.
  • Предотвращение простаивания потоков ОС (M) при наличии готовых к исполнению горутин в других очередях.

4. Очередь отложенных вызовов (Deferred Call Queue)

Каждая горутина имеет свой стек, где хранятся отложенные вызовы defer. Это не очередь в общепринятом смысле, но логически — LIFO-очередь defer-структур в стеке горутины.

5. Очередь каналов (Channel Operation Queues)

Каждый канал (chan) имеет две очереди ожидания:

  • sendq — горутины, заблокированные на отправке в полный канал.
  • recvq — горутины, заблокированные на получении из пустого канала.

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

Итог: сколько очередей?

Точное количество вариативно и зависит от:

  • Количества процессоров GOMAXPROCS — определяет число локальных очередей (по одной на P).
  • Количества каналов — каждый имеет по две очереди (sendq, recvq).
  • Констант: одна глобальная очередь (sched.runq).

Упрощённый расчёт для типичной программы:
Локальные очереди = GOMAXPROCS (например, 8)
+ Глобальная очередь = 1
+ Очереди каналов = 2 * количество_каналов
+ Деferred-очереди = количество_горутин (децентрализованно)

Таким образом, модель GMP использует распределённую систему очередей для минимизации конкуренции за ресурсы: большая часть работы выполняется через быстрые локальные очереди, а глобальная служит для балансировки и долгосрочного хранения. Эта архитектура — одна из ключевых причин высокой производительности планировщика Go при масштабировании на многоядерных системах.

Сколько есть очередей в модели GMP? | PrepBro