Ответ
Планирование горутин в Go — это процесс управления выполнением множества горутин на ограниченном количестве потоков операционной системы. Этим занимается встроенный в рантайм Go планировщик (scheduler).
Ключевая модель: M, P, G
Планировщик Go использует модель M:P:G:
- M (Machine): Поток операционной системы (OS Thread).
- P (Processor): Логический процессор, представляет собой контекст для выполнения кода Go. Количество P по умолчанию равно количеству ядер CPU (
runtime.GOMAXPROCS
). - G (Goroutine): Сама горутина, легковесный поток.
Планировщик распределяет горутины (G) для выполнения на логических процессорах (P), которые, в свою очередь, выполняются на системных потоках (M). Это позволяет эффективно использовать ресурсы CPU и управлять тысячами горутин на небольшом количестве потоков ОС.
Кооперативное вытеснение
Горутина уступает процессорное время в следующих случаях:
- Системные вызовы: при блокирующих операциях ввода-вывода (например, работа с сетью или файлами).
- Блокировка на каналах или мьютексах: когда горутина ждет данные или освобождения ресурса.
- Вызов
runtime.Gosched()
: явное указание планировщику переключиться на другую горутину. - Длительные циклы: начиная с Go 1.14, планировщик может вытеснить горутину, которая выполняется слишком долго (более 10 мс) без точек переключения.
Также планировщик реализует механизм "воровства работы" (work-stealing): если у одного P заканчиваются горутины в очереди, он может "украсть" их у другого P, чтобы избежать простоя.