errgroup

什么是errrgroup

在开发并发程序时,错误的收集和传播往往比较繁琐,有时候当一个错误发声时,我们需要停止所有相关任务,有时候却不是。sync.ErrGroup刚好可以解决我们上述的痛点,它提供错误传播,以及利用context的方式来决定是否要停止相关任务。

errrgroup.Group结构体

type Group struct {
	cancel func()
	wg sync.WaitGroup
	errOnce sync.Once
	err     error
}
``

三个对外api

```go
unc WithContext(ctx context.Context) (*Group, context.Context)
func (g *Group) Go(f func() error)
func (g *Group) Wait() error

使用errrgroup

只返回错误

package main

import (
	"fmt"
	"golang.org/x/sync/errgroup"
	"net/http"
)

func main() {
	var g errgroup.Group
	var urls = []string{
		"http://www.golang.org/",
		"http://www.111111111111111111111111.com/", //这个地址不存在
		"http://www.google.com/",
		"http://www.somestupidname.com/",
	}
	for _, url := range urls {
		url := url 
		g.Go(func() error {
			resp, err := http.Get(url)
			if err == nil {
				resp.Body.Close()
			}
			return err
		})
	}
	if err := g.Wait(); err == nil {
		fmt.Println("Successfully fetched all URLs.")
	}else {
		fmt.Println(err)
	}
}
$ go run main.go
www.111111111111111111111111.com:80: unknown error host unreachable

使用 errgroup.WithContext

package main

import (
	"context"
	"fmt"
	"golang.org/x/sync/errgroup"
	"net/http"
	"time"
)

func main() {
	ctx ,_:=context.WithTimeout(context.Background(),3*time.Second)
	var g ,_=  errgroup.WithContext(ctx)
	var urls = []string{
		"http://www.golang.org/",
		"http://www.111111111111111111111111.com/",
		"http://www.google.com/",
		"http://www.somestupidname.com/",
	}
	for _, url := range urls {
		url := url
		g.Go(func() error {
			ch := make(chan error)
			go func() {
				time.Sleep(4e9)
				resp, err := http.Get(url)
				if err == nil {
					resp.Body.Close()
				}
				ch <- err
			}()
			select {
            case err:= <-ch :
				return err
			case <-ctx.Done():
				return ctx.Err()
			}
		})
	}
	if err := g.Wait(); err == nil {
		fmt.Println("Successfully fetched all URLs.")
	}else {
		fmt.Println(err)
	}
}
$ go run main.go
context deadline exceeded