Что такое переключение контекста в Go и чем оно отличается от переключения на уровне ОС?

Ответ

Переключение контекста — это процесс сохранения состояния (контекста) текущей выполняемой задачи и восстановления состояния другой, чтобы та могла продолжить выполнение.

В Go речь идет о переключении контекста горутин, которое принципиально отличается от переключения контекста потоков операционной системы (ОС).

Ключевые отличия:

  1. Уровень выполнения:

    • Горутины: Управляются планировщиком Go (Go Scheduler) в пространстве пользователя (user space). Это очень "дешевая" операция.
    • Потоки ОС: Управляются ядром ОС (kernel space). Это "дорогая" операция, требующая перехода в режим ядра.
  2. Объем сохраняемого контекста:

    • Горутины: Сохраняется только необходимый минимум: указатель на инструкцию (program counter), указатели на стек и несколько регистров. Это занимает несколько сотен байт.
    • Потоки ОС: Сохраняется полный контекст потока, включая все регистры процессора, таблицы страниц памяти и т.д. Это занимает несколько килобайт.

Когда происходит переключение контекста в Go?

Планировщик Go переключает контекст, когда горутина:

  • Блокируется на операции ввода-вывода (например, чтение из сети или файла).
  • Блокируется при работе с каналами или мьютексами.
  • Выполняет системный вызов.
  • Явно уступает процессорное время через runtime.Gosched().
  • Выполняется слишком долго (начиная с Go 1.14, планировщик использует асинхронное прерывание для переключения долгоживущих горутин).
func main() {
    // Запускаем две горутины
    go func() {
        fmt.Println("Горутина 1: Начало")
        runtime.Gosched() // Явно просим планировщик переключиться
        fmt.Println("Горутина 1: Конец")
    }()

    go func() {
        fmt.Println("Горутина 2: Выполняется")
    }()

    // Даем время на выполнение горутин
    time.Sleep(time.Millisecond * 10)
}

Благодаря легковесности переключения контекста горутин, Go может эффективно управлять сотнями тысяч и даже миллионами одновременно выполняющихся горутин.