Проверяет понимание горутин в Go, их отличий от потоков ОС и модели управления планировщиком.
Горутина — это функция, которая выполняется конкурентно с другими горутинами в том же адресном пространстве. Она запускается ключевым словом go перед вызовом функции. Горутины являются основным инструментом конкурентного программирования в Go и позволяют писать асинхронный код без сложных колбэков.
Потоки ОС управляются ядром, имеют фиксированный стек (обычно 1–8 МБ) и требуют системных вызовов для создания и переключения. Горутины управляются планировщиком Go, имеют динамический стек (начинается с 2–8 КБ и растёт по мере необходимости), создаются за наносекунды и переключаются без перехода в режим ядра. Это позволяет запускать десятки тысяч горутин без деградации производительности.
Планировщик Go (runtime scheduler) использует модель M:N: он сопоставляет множество горутин (M) с меньшим числом потоков ОС (N). Планировщик распределяет горутины по потокам, обрабатывает блокировки (например, при системных вызовах) и переключает контекст. Внутри планировщик использует локальные и глобальные очереди горутин, а также механизм work stealing для балансировки нагрузки между потоками.
package main
import (
"fmt"
"time"
)
func printNumbers() {
for i := 1; i <= 5; i++ {
fmt.Println(i)
time.Sleep(100 * time.Millisecond)
}
}
func main() {
go printNumbers() // запуск горутины
time.Sleep(600 * time.Millisecond) // ждём завершения
fmt.Println("Главная функция завершена")
}Здесь printNumbers выполняется конкурентно с main. Планировщик сам решает, когда и на каком потоке выполнять горутину.
Горутины — это лёгкий и эффективный способ организации конкурентности в Go. Их стоит применять для параллельной обработки задач, сетевых операций и фоновых вычислений, когда важна масштабируемость и простота кода. Понимание планировщика помогает избегать гонок данных и эффективно использовать ресурсы.