1 // Copyright 2016 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 "golang.org/x/sync/errgroup"
19 Web = fakeSearch("web")
20 Image = fakeSearch("image")
21 Video = fakeSearch("video")
25 type Search func(ctx context.Context, query string) (Result, error)
27 func fakeSearch(kind string) Search {
28 return func(_ context.Context, query string) (Result, error) {
29 return Result(fmt.Sprintf("%s result for %q", kind, query)), nil
33 // JustErrors illustrates the use of a Group in place of a sync.WaitGroup to
34 // simplify goroutine counting and error handling. This example is derived from
35 // the sync.WaitGroup example at https://golang.org/pkg/sync/#example_WaitGroup.
36 func ExampleGroup_justErrors() {
37 g := new(errgroup.Group)
39 "http://www.golang.org/",
40 "http://www.google.com/",
41 "http://www.somestupidname.com/",
43 for _, url := range urls {
44 // Launch a goroutine to fetch the URL.
45 url := url // https://golang.org/doc/faq#closures_and_goroutines
48 resp, err := http.Get(url)
55 // Wait for all HTTP fetches to complete.
56 if err := g.Wait(); err == nil {
57 fmt.Println("Successfully fetched all URLs.")
61 // Parallel illustrates the use of a Group for synchronizing a simple parallel
62 // task: the "Google Search 2.0" function from
63 // https://talks.golang.org/2012/concurrency.slide#46, augmented with a Context
64 // and error-handling.
65 func ExampleGroup_parallel() {
66 Google := func(ctx context.Context, query string) ([]Result, error) {
67 g, ctx := errgroup.WithContext(ctx)
69 searches := []Search{Web, Image, Video}
70 results := make([]Result, len(searches))
71 for i, search := range searches {
72 i, search := i, search // https://golang.org/doc/faq#closures_and_goroutines
74 result, err := search(ctx, query)
81 if err := g.Wait(); err != nil {
87 results, err := Google(context.Background(), "golang")
89 fmt.Fprintln(os.Stderr, err)
92 for _, result := range results {
97 // web result for "golang"
98 // image result for "golang"
99 // video result for "golang"
102 func TestZeroGroup(t *testing.T) {
103 err1 := errors.New("errgroup_test: 1")
104 err2 := errors.New("errgroup_test: 2")
110 {errs: []error{nil}},
111 {errs: []error{err1}},
112 {errs: []error{err1, nil}},
113 {errs: []error{err1, nil, err2}},
116 for _, tc := range cases {
117 g := new(errgroup.Group)
120 for i, err := range tc.errs {
122 g.Go(func() error { return err })
124 if firstErr == nil && err != nil {
128 if gErr := g.Wait(); gErr != firstErr {
129 t.Errorf("after %T.Go(func() error { return err }) for err in %v\n"+
130 "g.Wait() = %v; want %v",
131 g, tc.errs[:i+1], err, firstErr)
137 func TestWithContext(t *testing.T) {
138 errDoom := errors.New("group_test: doomed")
145 {errs: []error{nil}, want: nil},
146 {errs: []error{errDoom}, want: errDoom},
147 {errs: []error{errDoom, nil}, want: errDoom},
150 for _, tc := range cases {
151 g, ctx := errgroup.WithContext(context.Background())
153 for _, err := range tc.errs {
155 g.Go(func() error { return err })
158 if err := g.Wait(); err != tc.want {
159 t.Errorf("after %T.Go(func() error { return err }) for err in %v\n"+
160 "g.Wait() = %v; want %v",
161 g, tc.errs, err, tc.want)
171 t.Errorf("after %T.Go(func() error { return err }) for err in %v\n"+
172 "ctx.Done() was not closed",