# Как устроен планировщик горутин в Go: G-M-P модель

Go использует уникальную модель управления конкурентностью — **G-M-P** (Goroutine, Machine, Processor), которая обеспечивает масштабируемость, высокую производительность и лёгкость работы с параллелизмом.

---

## <a id="bkmrk--1"></a>🧠 Компоненты Go-планировщика

<table class="table table-striped table-bordered" id="bkmrk-%D0%9E%D0%B1%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D0%B5-%D0%9D%D0%B0%D0%B7%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5"><thead><tr><th>Обозначение</th><th>Название</th><th>Что это такое</th></tr></thead><tbody><tr><td>**G**</td><td>Goroutine</td><td>Логическая единица выполнения (код + стек)</td></tr><tr><td>**M**</td><td>Machine (Thread)</td><td>Системный поток (OS thread)</td></tr><tr><td>**P**</td><td>Processor</td><td>Планировщик, управляющий выполнением G</td></tr></tbody></table>

---

## <a id="bkmrk--3"></a>🔄 Как это работает?

- **M (Thread)** — физический поток, выполняющий код
- **P (Processor)** — абстрактный процессор: даёт M-у задачу (G)
- **G (Goroutine)** — логическая задача, которую нужно выполнить

> M нужен P, чтобы выполнять G. Без P поток (M) простаивает.

---

## <a id="bkmrk--5"></a>🔁 Модель в действии

При запуске:

```
runtime.GOMAXPROCS(4)

```

Ты создаёшь 4 **P (процессора)**. Это означает, что Go может **одновременно** запускать до 4 горутин **в реальном параллелизме**.

---

## <a id="bkmrk--7"></a>🧬 Визуально:

```
+-------------+        +----------+        +------------------+
| Goroutine G |   -->  |   P      |  -->   | Thread M (OS)    |
+-------------+        +----------+        +------------------+
       ^                     |
       |_____________________|
         Work stealing (если P простаивает)

```

---

## <a id="bkmrk--9"></a>⏳ Work-stealing

Если один P (процессор) простаивает, он может “украсть” G из очереди другого P. Это делает систему ещё более гибкой и **минимизирует простои**.

---

## <a id="bkmrk--11"></a>📌 Примеры поведения

<table class="table table-striped table-bordered" id="bkmrk-%D0%A1%D1%86%D0%B5%D0%BD%D0%B0%D1%80%D0%B8%D0%B9-%D0%9A%D0%B0%D0%BA-%D1%81%D0%B5%D0%B1%D1%8F-%D0%B2%D0%B5"><thead><tr><th>Сценарий</th><th>Как себя ведёт Go</th></tr></thead><tbody><tr><td>1 млн горутин</td><td>Go спокойно справится</td></tr><tr><td>Ожидание по `time.Sleep`</td><td>P отходит от M и отдаёт другим</td></tr><tr><td>Блокировка I/O</td><td>M блокируется, но P берёт новый M</td></tr><tr><td>`runtime.GOMAXPROCS(n)`</td><td>Ограничивает кол-во одновременно исполняемых G</td></tr></tbody></table>

---

## <a id="bkmrk--13"></a>✅ Вывод:

Go-планировщик:

- работает по **G-M-P** модели
- очень эффективно управляет тысячами горутин
- масштабируется лучше, чем системы, построенные на потоках ОС
- делает конкурентное программирование простым и надёжным