Ответ
Нет, планировщик Go не является полностью вытесняющим (preemptive), он использует гибридную модель.
До Go 1.14 планировщик был в основном кооперативным. Это означало, что горутина уступала процессорное время другой горутине только в определенных точках (так называемых "safe points"):
- Вызовы функций (не для всех вызовов)
- Операции с каналами
- Системные вызовы
- Ожидание блокировок
Проблема этой модели была в том, что горутина с долгим циклом без вызовов функций могла надолго монополизировать поток ОС, не давая другим горутинам выполняться.
// Этот цикл без вызовов функций мог "подвесить" поток в версиях Go < 1.14
for {
// Никаких вызовов функций или каналов
}
Начиная с Go 1.14, было введено асинхронное вытеснение. Теперь планировщик может принудительно прервать горутину, если она выполняется слишком долго (более 10 мс) без кооперативного уступания. Это решает проблему "застрявших" циклов.
Итог:
- Основной механизм — кооперативная многозадачность в точках уступания.
- Страховочный механизм (с Go 1.14) — асинхронное вытеснение для долго работающих горутин.
Несмотря на улучшения, для написания отзывчивого кода все еще рекомендуется избегать очень длинных вычислений в циклах без точек уступания или при необходимости явно вызывать runtime.Gosched()
.