Какие существуют способы мониторинга состояния или завершения работы горутины?

Ответ

В Go нет встроенного механизма для получения статуса конкретной горутины извне (например, 'running', 'blocked'). Состояние горутин управляется исключительно рантаймом. Однако существуют стандартные паттерны для координации их работы и отслеживания завершения.

1. Каналы для сигнализации

Самый простой способ — использовать канал для отправки сигнала о завершении работы.

done := make(chan bool)

go func() {
    // ... какая-то полезная работа ...
    fmt.Println("Горутина завершает работу")
    close(done) // Закрываем канал, чтобы сигнализировать о завершении
}()

// Ожидаем сигнал в блокирующем режиме
<-done
fmt.Println("Основная программа получила сигнал о завершении горутины")

2. sync.WaitGroup для ожидания группы

Идеально подходит, когда нужно запустить несколько горутин и дождаться, пока они все завершат свою работу.

var wg sync.WaitGroup

for i := 0; i < 5; i++ {
    wg.Add(1) // Увеличиваем счетчик активных горутин
    go func(workerID int) {
        defer wg.Done() // Уменьшаем счетчик по завершении
        fmt.Printf("Воркер %d завершил работуn", workerID)
    }(i)
}

wg.Wait() // Блокируем выполнение, пока счетчик не станет равен нулю
fmt.Println("Все воркеры завершили работу")

3. context.Context для отмены

Контекст позволяет не просто ждать завершения, а управлять жизненным циклом горутины, например, отменить её выполнение.

ctx, cancel := context.WithCancel(context.Background())

go func(ctx context.Context) {
    for {
        select {
        case <-ctx.Done(): // Контекст был отменен
            fmt.Println("Горутина получила сигнал отмены, завершаюсь")
            return
        default:
            // ... выполнение работы ...
            time.Sleep(500 * time.Millisecond)
        }
    }
}(ctx)

time.Sleep(2 * time.Second)
cancel() // Отправляем сигнал отмены всем горутинам, слушающим этот контекст
time.Sleep(1 * time.Second) // Даем время горутине завершиться

Вывод: Выбор способа зависит от задачи: простой сигнал о завершении — канал, ожидание группы — WaitGroup, управление жизненным циклом и каскадная отмена — context.