WaitGroup
sync.WaitGroup
会阻塞在检查点,直到所有goroutine完成
func main(){
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
time.Sleep(time.Second)
fmt.Println(i)
}(i)
}
wg.Wait() //等待
}
errgroup
package main
import (
"fmt"
"log"
"time"
"golang.org/x/sync/errgroup"
)
func main() {
var eg errgroup.Group
for i := 0; i < 10; i++ {
i := i //这里要有局部变量,不然eg.Go()里面的i都是同一个数
eg.Go(func() error {
time.Sleep(time.Second)
if i > 5 {
fmt.Println("error: ", i)
return fmt.Errorf("error: i = %d", i)
}
fmt.Println(i)
return nil
})
}
if err := eg.Wait(); err != nil { //err是errgroup遇到第一个error
log.Fatal(err)
}
}
errgroup.WithContext()
可以通过上下文,当第一个goroutine遇到error时,配合select使其它goroutine得到消息,不再执行。
package main
import (
"context"
"fmt"
"log"
"time"
"golang.org/x/sync/errgroup"
)
func main() {
eg, ctx := errgroup.WithContext(context.Background())
for i := 0; i < 10; i++ {
i := i //这里要有局部变量,不然eg.Go()里面的i都是同一个数
eg.Go(func() error {
time.Sleep(time.Duration(i) * time.Second)
select {
case <-ctx.Done(): //errgroup内部有cancel()
fmt.Println("canceled: ", i)
return nil
default:
if i > 5 {
fmt.Println("error: ", i)
return fmt.Errorf("error: i = %d", i)
}
fmt.Println("end: ", i)
return nil
}
})
}
if err := eg.Wait(); err != nil { //err是errgroup遇到第一个error
log.Fatal(err)
}
}
end: 0
end: 1
end: 2
end: 3
end: 4
end: 5
error: 6
canceled: 7
canceled: 8
canceled: 9
2021/09/05 21:56:08 error: i = 6
- errgroup 结构体
type Group struct {
cancel func()
wg sync.WaitGroup
errOnce sync.Once //利用sync.Once只返回goroutine遇到的第一个err
err error
}