← Назад к вопросам

В каком случае горутина отдаст управление

2.7 Senior🔥 101 комментариев
#Конкурентность и горутины#Основы Go

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

В каком случае горутина отдаст управление?

Горутина в Go — это легковесный поток выполнения, управление которым осуществляется планировщиком Go (scheduler). В отличие от потоков ОС, горутины активно взаимодействуют с планировщиком для эффективного использования ресурсов. Горутина добровольно отдаёт управление в нескольких ключевых сценариях, что позволяет реализовать кооперативную многозадачность. Вот основные случаи:

1. При выполнении блокирующих операций ввода-вывода

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

resp, err := http.Get("https://example.com") // Блокирующий сетевой вызов

На время ожидания ответа горутина будет вытеснена.

2. При явном вызове планировщика

Использование функции runtime.Gosched() явно указывает планировщику переключиться на другую горутину. Это полезно для долгих вычислений, чтобы избежать голодания других горутин.

func worker() {
    for i := 0; i < 10; i++ {
        fmt.Println(i)
        runtime.Gosched() // Добровольно уступаем управление
    }
}

3. При синхронизации через каналы

Операции отправки (ch <- data) или получения (<-ch) на каналах часто блокируют горутину до тех пор, пока другая горутина не будет готова к взаимодействию. Планировщик переключает контекст.

ch := make(chan int)
go func() {
    ch <- 42 // Может заблокироваться, если нет получателя
}()
value := <-ch // Может заблокироваться, если нет отправителя

4. При использовании примитивов синхронизации

Пакет sync предоставляет мьютексы (sync.Mutex), RWMutex, WaitGroup и другие. При вызове Lock() на занятом мьютексе горутина блокируется и отдаёт управление.

var mu sync.Mutex
mu.Lock() // Блокируется, если мьютекс уже захвачен

5. При системных вызовах и вызове C-кода

Работа с cgo или вызовы, которые переводят горутину в режим ожидания ОС, также приводят к переключению.

6. При работе со временем

Использование time.Sleep() или операций с таймерами (time.After, time.Ticker) явно освобождает процессор.

time.Sleep(100 * time.Millisecond) // Горутина уходит в сон

7. При сборке мусора (GC)

Во время стоп-мира (stop-the-world) сборщик мусора может приостановить все горутины. Это не добровольная передача управления, но важно для понимания работы среды выполнения.

8. При исчерпании кванта времени

Хотя Go использует кооперативную многозадачность, планировщик также включает вытесняющую составляющую. Начиная с Go 1.14, горутина может быть вытеснена, если она:

  • Выполняет цикл без точек вытеснения (например, бесконечный цикл без вызовов функций).
  • Исполняется дольше 10 мс на одном ядре.

Ключевой принцип: кооперативность

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

Пример опасного кода без точек вытеснения:

func busyLoop() {
    for i := 0; ; i++ { // Бесконечный цикл без вызовов — может заблокировать планировщик
        // Только с Go 1.14+ такая горутина будет вытеснена через 10 мс
    }
}

Итог

Горутина отдаёт управление планировщику в следующих случаях:

  • Блокирующие операции (I/O, системные вызовы).
  • Синхронизация (каналы, мьютексы, WaitGroup).
  • Явный вызов runtime.Gosched().
  • Работа со временем (Sleep, таймеры).
  • При сборке мусора (принудительно).
  • По истечении кванта времени (с Go 1.14+).

Этот механизм позволяет эффективно использовать ресурсы CPU и избегать типичных проблем параллелизма, таких как инверсия приоритетов. Понимание этих принципов критично для написания эффективных и отзывчивых конкурентных программ на Go.

В каком случае горутина отдаст управление | PrepBro