Кооперативная vs Вытесняющая многозадачность: в чем разница и как это реализовано в Go?

Ответ

Это два фундаментальных подхода к управлению несколькими задачами в системе.

Кооперативная многозадачность (Cooperative Multitasking)

Задачи (процессы, потоки, горутины) должны добровольно отдавать управление планировщику. Если одна задача зависнет в долгом цикле без вызова специальной функции (условного yield()), она заблокирует выполнение всех остальных задач.

  • Плюсы: Простая реализация планировщика.
  • Минусы: Ненадежность. Одна плохо написанная задача может "подвесить" всю систему.

Вытесняющая многозадачность (Preemptive Multitasking)

Планировщик (ОС или рантайм) может принудительно прервать выполнение задачи в любой момент, чтобы передать управление другой. Задаче не нужно "сотрудничать".

  • Плюсы: Надежность и отзывчивость. Ни одна задача не может монополизировать процессор.
  • Минусы: Более сложная реализация, требует механизма сохранения и восстановления контекста.

Реализация в Go

Планировщик Go прошел эволюцию:

  • До Go 1.14: Горутины использовали преимущественно кооперативную модель. Планировщик мог переключить контекст только в "безопасных точках" (safe points) — при вызовах функций, операциях с каналами, системных вызовах. Длинный цикл без таких вызовов (for {}) мог занять ядро на неопределенное время.

  • С Go 1.14: Была добавлена асинхронная вытесняющая многозадачность. Теперь рантайм Go может принудительно остановить горутину, которая выполняется слишком долго (например, более 10 мс), даже если в ней нет вызовов функций. Это делает планировщик более справедливым и предотвращает "зависание" отдельных потоков ОС.