Ответ
В Go планировщик (scheduler) управляет горутинами, используя три основных состояния:
- Runnable - горутина готова к выполнению, но ожидает свободного потока (M)
- Running - горутина выполняется в потоке
- Waiting - горутина заблокирована (I/O, каналы, мьютексы)
Планировщик использует очередь runqueue (глобальную и локальные для каждого P) для хранения Runnable-горутин. Каждый логический процессор (P) выбирает следующую горутину по алгоритму work-stealing.
Пример перехода состояний:
func worker() {
// Running -> Waiting (блокировка)
time.Sleep(time.Second)
// Waiting -> Runnable
// Runnable -> Running (когда планировщик выделит поток)
}