go-hep.org/x/hep@v0.38.1/fwk/utils/parallel/parallel.go (about) 1 // Copyright ©2017 The go-hep 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 5 // the following has been extracted from Rog Peppe's parallel package 6 // published under the new BSD-3 clause license 7 // http://opensource.org/licenses/BSD-3-Clause 8 // 9 // original sources are available at: 10 // code.google.com/p/rog-go/parallel 11 12 // The parallel package provides a way of running functions 13 // concurrently while limiting the maximum number 14 // running at once. 15 package parallel // import "go-hep.org/x/hep/fwk/utils/parallel" 16 17 import ( 18 "fmt" 19 "sync" 20 ) 21 22 // Run represents a number of functions running concurrently. 23 type Run struct { 24 limiter chan struct{} 25 done chan error 26 err chan error 27 wg sync.WaitGroup 28 } 29 30 // Errors holds any errors encountered during 31 // the parallel run. 32 type Errors []error 33 34 func (errs Errors) Error() string { 35 switch len(errs) { 36 case 0: 37 return "no error" 38 case 1: 39 return errs[0].Error() 40 } 41 return fmt.Sprintf("%s (and %d more)", errs[0].Error(), len(errs)-1) 42 } 43 44 // NewRun returns a new parallel instance. It will run up to maxPar 45 // functions concurrently. 46 func NewRun(maxPar int) *Run { 47 r := &Run{ 48 limiter: make(chan struct{}, maxPar), 49 done: make(chan error), 50 err: make(chan error), 51 } 52 go func() { 53 var errs Errors 54 for e := range r.done { 55 errs = append(errs, e) 56 } 57 // TODO sort errors by original order of Do request? 58 if len(errs) > 0 { 59 r.err <- errs 60 } else { 61 r.err <- nil 62 } 63 }() 64 return r 65 } 66 67 // Do requests that r run f concurrently. If there are already the maximum 68 // number of functions running concurrently, it will block until one of 69 // them has completed. Do may itself be called concurrently. 70 func (r *Run) Do(f func() error) { 71 r.limiter <- struct{}{} 72 r.wg.Add(1) 73 go func() { 74 defer func() { 75 r.wg.Done() 76 <-r.limiter 77 }() 78 if err := f(); err != nil { 79 r.done <- err 80 } 81 }() 82 } 83 84 // Wait marks the parallel instance as complete and waits for all the 85 // functions to complete. If any errors were encountered, it returns an 86 // Errors value describing all the errors in arbitrary order. 87 func (r *Run) Wait() error { 88 r.wg.Wait() 89 close(r.done) 90 return <-r.err 91 }