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

Какие процессы переводит горутина в ожидание?

1.8 Middle🔥 231 комментариев
#Конкурентность и горутины#Основы Go

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

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

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

Состояния горутин и переход в ожидание

В Go горутина — это легковесная единица выполнения, управляемая планировщиком (runtime scheduler). Планировщик переводит горутины в различные состояния для эффективного распределения ресурсов CPU. Ожидание (waiting) — одно из ключевых состояний, в которое горутина переходит при определенных условиях.

Основные причины перехода горутины в ожидание

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

1. Блокировка на операциях синхронизации

Это наиболее частые случаи:

  • Ожидание на каналах (channels): при отправке (ch <- value) или получении (value <- ch) данных, если операция не может быть выполнена мгновенно (канал небуферизованный или буфер заполнен/пуст).
  • Ожидание на мьютексах (mutexes): при вызове Lock() на уже заблокированном мьютексе (sync.Mutex, sync.RWMutex).
  • Ожидание на группах ожидания (wait groups): вызов Wait() на sync.WaitGroup.
  • Ожидание на условных переменных (conditions): sync.Cond.
// Пример: ожидание на небуферизованном канале
ch := make(chan int)
go func() {
    // Горутина заблокируется здесь, пока другая не отправит данные
    value := <-ch
    fmt.Println(value)
}()

2. Блокировка на системных вызовах или операциях с файловой системой

  • Сетевые операции (net пакет): чтение/запись через сеть (TCP, UDP).
  • Операции с файлами (os пакет): чтение/запись файлов, особенно если данные не готовы.
  • Системные вызовы (syscalls): любые вызовы, которые переводят процесс в режим ожидания ОС (например, sleep).
// Пример: сетевой запрос
resp, err := http.Get("https://example.com")
// Горутина заблокируется на время выполнения сетевого запроса

3. Блокировка на вызове time.Sleep

Прямой перевод горутины в ожидание на заданный интервал. Планировщик «ставит её на паузу».

// Горутина переходит в ожидание на 2 секунды
time.Sleep(2 * time.Second)

4. Блокировка на операциях с таймерами или контекстами

  • Таймеры (time.Timer, time.Ticker): ожидание сигнала от таймера (<-timer.C).
  • Контексты (context.Context): ожидание сигнала отмены или deadline (<-ctx.Done()).

5. Блокировка на вызове runtime.Gosched

Добровольная уступка процессорного времени. Горутина переходит в ожидание, чтобы дать шанс другим горутинам.

// Горутина добровольно уступает планировщику
runtime.Gosched()

Как планировщик управляет ожидающими горутинами

Когда горутина переходит в ожидание, планировщик:

  1. Снимает её с текущего потока (M), который выполнялся на ядре CPU.
  2. Переводит её состояние в Gwaiting (внутреннее состояние runtime).
  3. Сохраняет связанные данные (например, канал, на котором она заблокирована) для будущего возобновления.
  4. Выбирает другую готовую горутину (Grunnable) из локальной или глобальной очереди и запускает её.

Когда условие ожидания удовлетворяется (например, данные поступают в канал), горутина переводится обратно в состояние Grunnable и помещается в очередь для выполнения.

Ключевые моменты

  • Ожидание — это не блокировка потока (thread). Один поток ОС (M в runtime Go) может выполнять множество горутин, переключаясь между ними, когда они блокируются.
  • Это основа для эффективной обработки тысяч одновременных операций в Go, особенно в серверных приложениях.
  • Большинство переходов в ожидание происходят автоматически при использовании стандартных механизмов синхронизации Go (каналы, мьютексы).

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

Какие процессы переводит горутина в ожидание? | PrepBro