Использование гороутин
Подскажите пожалуйста, как реализовать грамотно такой алгоритм, используя функицонал Go:
запускаются несколько гороутин, которые возвращают результат, каждая - в произвольный момент времени.
если таймаут - завершаем все работающие горутины
если какая-либо гороутина вернула результат, то
3а) если результат положительный, то завершаем все остальные работающие горутины
3б) иначе - ждем результата от следующей гороутины
answers := make(chan UpstreamAnswer, len(upstream_list)) var result int = 0 // запускаем гороутины for _, dl := range upstream_list { go test_conn(cx, dl.idx, proto, host_req, port_req, answers) } // ждем ответа(ов) for i := 0; i < 100; i++ { select { case dialer = <-answers: // проверяем ответ, если ОК - выходим из цикла if dialer.OK { result = dialer.idx } case <-time.After(time.Millisecond * 100): // тут еще какая-то работа идет периодически } if result != 0 { break } } // завершаем гороутины через контекст cancel() close(answers) // здесь проверяем уже результат if result ...
Ответы (1 шт):
Автор решения: Borislav
→ Ссылка
type Result struct {
isPositive bool
}
var i int
func doSomeWorkForProvideResult() Result {
defer func() {
i++
}()
if i > 100 {
return Result{true}
}
return Result{}
}
func main() {
ch := make(chan Result)
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
const timeout = time.Second * 10
timer := time.NewTimer(timeout)
defer timer.Stop()
for w := 0; w < runtime.NumCPU(); w++ {
go func() {
for {
select {
case <-ctx.Done():
return
default:
if res := doSomeWorkForProvideResult(); res.isPositive {
ch <- res
cancel()
return
}
}
}
}()
}
go func() {
for {
select {
case <-ctx.Done():
return
case <-timer.C:
cancel()
return
}
}
}()
res := <-ch
fmt.Printf("found positive result: %+v\n", res)
}