WaitGroup
- это один из способов, однако команда Go представила errgroup
для вашего случая использования.Самая неудобная часть ответа листового бибопа - игнорирование обработки ошибок.Обработка ошибок - причина существования errgroup
.Идиоматический код go не должен никогда глотать ошибки.
Однако, сохраняя подписи вашей Foo
структуры (кроме косметической workerNumber
) - и не обрабатывая ошибок - мое предложение выглядит так:
package main
import (
"fmt"
"math/rand"
"time"
"golang.org/x/sync/errgroup"
)
type Foo struct {
errg errgroup.Group
}
func NewFoo() *Foo {
foo := &Foo{
errg: errgroup.Group{},
}
return foo
}
func (a *Foo) Bar(workerNumber int) {
a.errg.Go(func() error {
select {
// simulates the long running clals
case <-time.After(time.Second * time.Duration(rand.Intn(10))):
fmt.Println(fmt.Sprintf("worker %d completed its work", workerNumber))
return nil
}
})
}
func (a *Foo) Close() {
a.errg.Wait()
}
func main() {
foo := NewFoo()
for i := 0; i < 10; i++ {
foo.Bar(i)
}
<-time.After(time.Second * 5)
fmt.Println("Waiting for workers to complete...")
foo.Close()
fmt.Println("Done.")
}
Преимущество здесь, если вы вводите обработку ошибок в свой код (вам следует), вам нужно лишь слегка изменить этот код: вкратце, errg.Wait()
вернет первую ошибку redis, а Close()
может распространить это вверх по стеку (на главную, в данном случае).
Используя пакет context.Context
, вы также сможете немедленно отменить любой запущенный вызов redis, если произойдет сбой.Примеры этого есть в документации errgroup
.