errgroup.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  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.
  4. // Package errgroup provides synchronization, error propagation, and Context
  5. // cancelation for groups of goroutines working on subtasks of a common task.
  6. package errgroup
  7. import (
  8. "sync"
  9. "golang.org/x/net/context"
  10. )
  11. // A Group is a collection of goroutines working on subtasks that are part of
  12. // the same overall task.
  13. //
  14. // A zero Group is valid and does not cancel on error.
  15. type Group struct {
  16. cancel func()
  17. wg sync.WaitGroup
  18. errOnce sync.Once
  19. err error
  20. }
  21. // WithContext returns a new Group and an associated Context derived from ctx.
  22. //
  23. // The derived Context is canceled the first time a function passed to Go
  24. // returns a non-nil error or the first time Wait returns, whichever occurs
  25. // first.
  26. func WithContext(ctx context.Context) (*Group, context.Context) {
  27. ctx, cancel := context.WithCancel(ctx)
  28. return &Group{cancel: cancel}, ctx
  29. }
  30. // Wait blocks until all function calls from the Go method have returned, then
  31. // returns the first non-nil error (if any) from them.
  32. func (g *Group) Wait() error {
  33. g.wg.Wait()
  34. if g.cancel != nil {
  35. g.cancel()
  36. }
  37. return g.err
  38. }
  39. // Go calls the given function in a new goroutine.
  40. //
  41. // The first call to return a non-nil error cancels the group; its error will be
  42. // returned by Wait.
  43. func (g *Group) Go(f func() error) {
  44. g.wg.Add(1)
  45. go func() {
  46. defer g.wg.Done()
  47. if err := f(); err != nil {
  48. g.errOnce.Do(func() {
  49. g.err = err
  50. if g.cancel != nil {
  51. g.cancel()
  52. }
  53. })
  54. }
  55. }()
  56. }