Остановка горутины
Всем привет. Стоит задача: Реализовать остановку горутины. Я делаю так:
package main
import (
"log"
"sync"
)
func Work(data []int, lendata int, wg *sync.WaitGroup) {
quite := make(chan bool)
for i := 0; i < lendata; i++ {
go func(i int) {
log.Println(data[i])
wg.Done()
select {
case <-quite:
return
default:
}
}(i)
}
log.Println("EXIT")
quite <- true
}
func main() {
slc := make([]int, 0)
slc = append(slc, 12, 32, 65, 34, 54, 87)
wg := sync.WaitGroup{}
lendata := len(slc)
wg.Add(lendata)
Work(slc, lendata, &wg)
wg.Wait()
}
В выводе я получаю
2022/05/14 14:21:18 EXIT
2022/05/14 14:21:18 32
2022/05/14 14:21:18 12
2022/05/14 14:21:18 34
2022/05/14 14:21:18 65
2022/05/14 14:21:18 54
2022/05/14 14:21:18 87
//порядок естесстенно разный у чисел
В моем понимании, после первого прохода цикла горутина должна остановиться и остальные проходы не выполниться или я не прав?
package main
import (
"log"
"sync"
)
//wg.Done() вызывает deadlock и панику, куда бы я его не поставил
//поэтому в этом примере я его не ставлю, так как возможно проблема уже здесь
func Work(data []int, wg *sync.WaitGroup) {
quite := make(chan bool)
go func() {
for _, item := range data {
log.Println(item)
select {
case <-quite:
return
default:
}
}
}()
log.Println("EXIT")
quite <- true
}
func makechan() {
slc := make([]int, 0)
slc = append(slc, 12, 32, 65, 34, 54, 87)
wg := sync.WaitGroup{}
lendata := len(slc)
wg.Add(lendata)
Work(slc, &wg)
wg.Wait()
}
Ожидаемое поведение: после первого прохода цикла горутина останавливается не вызывая панику по deadlock. Моя догадка6 не нужно использовать waitgroup
Я сделал такой пример, но он зацикливается на пустом default в Work()
Ответы (1 шт):
Во-первых: вам не подойдет канал для закрытия НЕСКОЛЬКИХ горутин с 1 сообщением, тк горутин больше чем 1 (разве чт опроверять не читает ли горутина закрытый канал). Другие горутины слушают канал, но от туда ничего не придет — первая горутина вычитала сообщение из канала (то есть забрала его), а в канал никто ничего больше не шлет и др горутины не дождутся сообщения
Во-вторых: Если используете select/case только для прослушка сигнала о закрытии, то нужно обернуть в бесконечный цикл for, чтобы она не была припаркована, тк выполнится default у вас и все — дальше выполняться нечему. А если сейчас for добавить и wg.Done() перед return — программа не завершится (тк горутины не завершатся, тк завершится только первая из них (прошлый пункт))
В-третьих (итог): лучше использовать контекст, вот ответ на ваш вопрос от меня с примером Потoкобезопасное завершение программы