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

Ответ

Для явной передачи управления планировщику Go используется функция runtime.Gosched().

Вызов runtime.Gosched() уступает процессор (yields the processor), позволяя планировщику запустить другую горутину. Текущая горутина приостанавливается и помещается в конец очереди готовых к выполнению горутин, чтобы продолжить работу позже.

Пример:

package main

import (
    "fmt"
    "runtime"
)

func main() {
    go func() {
        for i := 0; i < 5; i++ {
            fmt.Println("Горутина 1:", i)
        }
    }()

    for i := 0; i < 5; i++ {
        // Даем шанс выполниться другим горутинам
        runtime.Gosched()
        fmt.Println("Главная горутина:", i)
    }
}

Когда это нужно?

На практике runtime.Gosched() используется крайне редко. Планировщик Go является вытесняющим (preemptive) и эффективно распределяет время между горутинами самостоятельно, делая паузы на вызовах функций. Явный вызов может понадобиться в специфических случаях:

  1. Длительные циклы без вызовов функций: Если у вас есть цикл, который выполняет только математические вычисления без I/O или вызовов других функций, он может надолго занять ядро, не давая другим горутинам выполняться. Вставка runtime.Gosched() в такой цикл решает эту проблему.
  2. Тестирование и отладка: Для воспроизведения состояний гонки (race conditions) или для тестирования сложного конкурентного кода.