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

В каком случае горутина может быть переключена

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

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

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

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

Когда горутина может быть переключена

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

1. Системные вызовы (syscalls)

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

file, err := os.Open("data.txt") // Системный вызов - горутина может быть переключена

2. Операции с каналами

Блокирующие операции с каналами (чтение/запись) явно позволяют переключиться на другую горутин.

ch := make(chan int)
go func() {
    ch <- 42 // Если канал не готов к чтению, горутина может быть переключена
}()
val := <-ch // Если канал пуст, горутина читателя может быть переключена

3. Вызовы runtime.Gosched()

Явный вызов runtime.Gosched() уступает текущий поток, позволяя планировщику запустить другие горутины.

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

4. Работа с синхронизацией (mutex, waitgroup)

При использовании мьютексов, sync.WaitGroup или других механизмов синхронизации горутина может быть переключена, если ресурс заблокирован.

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

5. Вытеснение (preemption)

Современный планировщик Go (с версии 1.14) использует вытеснение на основе сигналов, чтобы предотвратить "монополизацию" потока одной горутиной. Это происходит:

  • При длительных вычислениях без точек вытеснения (например, tight loop без системных вызовов/сетевых операций).
  • По сигналам от операционной системы (например, на Linux через SIGURG).
for i := 0; i < 1000000000; i++ { // Длительный цикл может вызвать вытеснение
    // Логика без блокирующих вызовов
}

6. Вызовы функций, которые могут блокировать

Некоторые функции из стандартной библиотеки или runtime могут создавать точки переключения.

Механизм переключения в деталях

Планировщик Go работает на уровне M (машин, потоков ОС), G (горутин) и P (процессоров, контекстов). Переключение происходит когда:

  1. Горутина блокируется (канал, мьютекс, системный вызов).
  2. Горутина завершает выполнение.
  3. Планировщик решает вытеснить горутин по сигналу или для балансировки нагрузки.
  4. Явный вызов runtime.Gosched().

Пример демонстрации переключения

Рассмотрим пример с длительным циклом и вытеснением:

package main

import (
    "fmt"
    "runtime"
    "time"
)

func greedyGoroutine() {
    for i := 0; i < 1000000000; i++ {
        // Плотные вычисления без точек вытеснения
        if i % 100000000 == 0 {
            fmt.Println("Greedy:", i) // Периодические выводы могут создавать точки
        }
    }
}

func normalGoroutine(id int) {
    for i := 0; i < 5; i++ {
        fmt.Println("Normal", id, ":", i)
        time.Sleep(100 * time.Millisecond) // Sleep создает точку переключения
    }
}

func main() {
    runtime.GOMAXPROCS(1) // Ограничим одним потоком для демонстрации
    go greedyGoroutine()
    for i := 0; i < 3; i++ {
        go normalGoroutine(i)
    }
    time.Sleep(2 * time.Second)
}

В этом примере даже с одним потоком горутина greedyGoroutine будет периодически вытесняться, позволяя normalGoroutine выполнять свою работу благодаря time.Sleep и вытеснению.

Ключевые выводы

  • Переключение горутин происходит кооперативно через блокирующие операции и вытеснение для длительных вычислений.
  • Планировщик старается минимизировать латентность и максимизировать utilization потоков ОС.
  • Нет гарантий порядка переключения — это зависит от планировщика и состояния системы.

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

В каком случае горутина может быть переключена | PrepBro