Планировщик Go управляет горутинами, потоками операционной системы и логическими процессорами, используя модель GMP:
- G (Goroutine): Легковесная, независимая единица выполнения. Содержит стек, указатель на инструкцию и другую информацию о состоянии. Множество горутин могут работать на одном потоке ОС.
- M (Machine): Поток операционной системы. Выступает в роли исполнителя, запускающего код горутины. Множество M может быть доступно для планировщика.
- P (Processor): Логический процессор. Предоставляет контекст для выполнения горутины. Содержит локальную очередь горутин, которые готовы к выполнению на данном M. Количество P по умолчанию равно
runtime.NumCPU().
Взаимодействие:
- Горутина (G) создается и помещается в глобальную или локальную очередь P.
- Свободный поток M запрашивает P. Если P доступен, M привязывается к нему.
- M берет горутину из локальной очереди P и начинает ее выполнение.
- Если горутина блокируется (например, при ожидании I/O), M отсоединяется от P ("hand off"). P остается доступным для другого M или планирует другую горутину из своей очереди.
- Когда блокированная горутина готова к возобновлению, она помещается обратно в очередь P или глобальную очередь.
- M может быть создан планировщиком при необходимости (например, если все существующие M заблокированы) или удален при неактивности.
Preemption (принудительное переключение): Планировщик может прервать выполнение горутины после определенного периода времени (time slice), чтобы гарантировать справедливое распределение процессорного времени между другими горутинами.
Work Stealing (кража работы): Если P исчерпал горутины в своей локальной очереди, он может попытаться "украсть" горутины из глобальной очереди или очередей других P.