Ответ
В 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
.