Ответ
Нет, не в классическом понимании. Планировщик Go использует модель кооперативной многозадачности с асинхронным вытеснением (начиная с Go 1.14).
1. Кооперативная многозадачность:
Планировщик Go передает управление другой горутине в так называемых "безопасных точках" (safe-points). Горутина добровольно уступает процессор, когда выполняет:
- Операции с каналами (отправка или получение).
- Системные вызовы (например, чтение файла или сетевой запрос).
- Блокировки мьютексов.
- Явный вызов
runtime.Gosched()
.
Проблема: Если горутина выполняет долгий вычислительный цикл без этих операций, она может надолго монополизировать поток операционной системы, не давая другим горутинам выполняться на этом потоке.
// В версиях Go < 1.14 этот код мог заблокировать поток
func main() {
go func() {
// Бесконечный цикл без точек переключения
for { }
}()
time.Sleep(time.Second)
fmt.Println("Эта горутина может никогда не получить управление")
}
2. Асинхронное вытеснение (Go 1.14+):
Для решения проблемы долгих циклов в Go 1.14 была добавлена механика асинхронного вытеснения. Если горутина работает дольше определенного кванта времени (например, 10 мс), рантайм посылает ей сигнал, который приостанавливает ее выполнение и позволяет планировщику запустить другую горутину.
Это делает планировщик более справедливым и устойчивым, но runtime.Gosched()
все еще остается полезным для тонкого управления и явной передачи управления в критических участках кода.