go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/sync/parallel/workPool.go (about) 1 // Copyright 2015 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package parallel 16 17 import ( 18 "go.chromium.org/luci/common/errors" 19 ) 20 21 // WorkPool creates a fixed-size pool of worker goroutines. A supplied generator 22 // method creates task functions and passes them through to the work pool. 23 // 24 // WorkPool will use at most workers goroutines to execute the supplied tasks. 25 // If workers is <= 0, WorkPool will be unbounded and behave like FanOutIn. 26 // 27 // WorkPool blocks until all the generator completes and all workers have 28 // finished their tasks. 29 func WorkPool(workers int, gen func(chan<- func() error)) error { 30 return multiErrorFromErrors(Run(workers, gen)) 31 } 32 33 // FanOutIn is useful to quickly parallelize a group of tasks. 34 // 35 // You pass it a function which is expected to push simple `func() error` 36 // closures into the provided chan. Each function will be executed in parallel 37 // and their error results will be collated. 38 // 39 // The function blocks until all functions are executed, and an 40 // errors.MultiError is returned if one or more of your fan-out tasks failed, 41 // otherwise this function returns nil. 42 // 43 // This function is equivalent to WorkPool(0, gen). 44 func FanOutIn(gen func(chan<- func() error)) error { 45 return WorkPool(0, gen) 46 } 47 48 // multiErrorFromErrors takes an error-channel, blocks on it, and returns 49 // a MultiError for any errors pushed to it over the channel, or nil if 50 // all the errors were nil. 51 func multiErrorFromErrors(ch <-chan error) error { 52 if ch == nil { 53 return nil 54 } 55 ret := errors.MultiError(nil) 56 for e := range ch { 57 if e == nil { 58 continue 59 } 60 ret = append(ret, e) 61 } 62 if len(ret) == 0 { 63 return nil 64 } 65 return ret 66 }