Go scheduler использует асинхронную preemption (с Go 1.14). До этого была только кооперативная — горутина уступала управление только в определённых точках.
Кооперативная preemption (точки уступки):
- Вызов функции (function call)
- Операции с каналами
- Системные вызовы
runtime.Gosched()
go func() {
for { // tight loop без вызовов функций
// горутина НИКОГДА не уступит CPU!
// блокирует весь P (процессор)
}
}()
Асинхронная preemption (Go 1.14+): Рантайм шлёт сигнал (SIGURG на Unix) горутине, работающей >10мс. Горутина прерывается в safe point — где GC может корректно просканировать стек.
Как работает:
1. sysmon (системный мониторинг) обнаруживает горутину, работающую >10мс
2. Шлёт асинхронный сигнал потоку
3. Signal handler сохраняет состояние и переключает горутину
Теперь даже tight-loop без вызовов функций будет прерван. Это решило проблемы с latency и GC-паузами.