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.
16 "golang.org/x/sync/errgroup"
19 // Pipeline demonstrates the use of a Group to implement a multi-stage
20 // pipeline: a version of the MD5All function with bounded parallelism from
21 // https://blog.golang.org/pipelines.
22 func ExampleGroup_pipeline() {
23 m, err := MD5All(context.Background(), ".")
28 for k, sum := range m {
29 fmt.Printf("%s:\t%x\n", k, sum)
38 // MD5All reads all the files in the file tree rooted at root and returns a map
39 // from file path to the MD5 sum of the file's contents. If the directory walk
40 // fails or any read operation fails, MD5All returns an error.
41 func MD5All(ctx context.Context, root string) (map[string][md5.Size]byte, error) {
42 // ctx is canceled when g.Wait() returns. When this version of MD5All returns
43 // - even in case of error! - we know that all of the goroutines have finished
44 // and the memory they were using can be garbage-collected.
45 g, ctx := errgroup.WithContext(ctx)
46 paths := make(chan string)
50 return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
54 if !info.Mode().IsRegular() {
66 // Start a fixed number of goroutines to read and digest files.
67 c := make(chan result)
68 const numDigesters = 20
69 for i := 0; i < numDigesters; i++ {
71 for path := range paths {
72 data, err := ioutil.ReadFile(path)
77 case c <- result{path, md5.Sum(data)}:
90 m := make(map[string][md5.Size]byte)
94 // Check whether any of the goroutines failed. Since g is accumulating the
95 // errors, we don't need to send them (or check for them) in the individual
96 // results sent on the channel.
97 if err := g.Wait(); err != nil {