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  }