Ответ
В 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.
Ответ 18+ 🔞
Вот же ж, классическая история, как в том анекдоте про Герасима! Хочешь узнать, жива ли твоя горутина, а она тебе — ни гу-гу, как немой крестьянин. В Go, блядь, нет такого встроенного волшебного окошка, чтобы посмотреть на каждую горутину и сказать: "Ага, эта — бежит, а эта — уснула, ждёт канал, как дура". Рантайм сам этим заправляет, а нам, смертным, дают только костыли, но костыли охуенные!
1. Каналы — классика, как "Муму"
Самый простой способ, чтобы горутина крикнула: "Всё, я закончила, можете меня не ждать!". Делаем канал и закрываем его в конце.
done := make(chan bool)
go func() {
// ... какая-то полезная работа ...
fmt.Println("Горутина завершает работу")
close(done) // Закрываем канал, чтобы сигнализировать о завершении
}()
// Ожидаем сигнал в блокирующем режиме
<-done
fmt.Println("Основная программа получила сигнал о завершении горутины")
Вот и всё, элементарно. Главное не забыть закрыть, а то будешь ждать, как Герасим у реки, а сигнала всё нет и нет.
2. sync.WaitGroup — для толпы
А если у тебя не одна горутина, а целая орава, как те ткачихи у царя? Запустил пять штук, и как понять, когда все зашились? Надо ждать последнюю! Для этого есть WaitGroup — счётчик, ёпта.
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1) // Запустили одну — добавили в счётчик, чтоб не потерялась
go func(workerID int) {
defer wg.Done() // Сделала дело — отняла себя из счётчика. Обязательно через defer, а то забудешь!
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 твой выбор.
А статус "running" или "blocked" — это тайна за семью печатями рантайма, туда лучше не лезть, а то охуеешь.