Ответ
Переключение контекста — это процесс сохранения состояния (контекста) текущей выполняемой задачи и восстановления состояния другой, чтобы та могла продолжить выполнение.
В Go речь идет о переключении контекста горутин, которое принципиально отличается от переключения контекста потоков операционной системы (ОС).
Ключевые отличия:
Уровень выполнения:
- Горутины: Управляются планировщиком Go (Go Scheduler) в пространстве пользователя (user space). Это очень "дешевая" операция.
- Потоки ОС: Управляются ядром ОС (kernel space). Это "дорогая" операция, требующая перехода в режим ядра.
Объем сохраняемого контекста:
- Горутины: Сохраняется только необходимый минимум: указатель на инструкцию (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 может эффективно управлять сотнями тысяч и даже миллионами одновременно выполняющихся горутин.