Search code examples
goconcurrencychannelgoroutine

Go Accept from the fastest worker function


Please consider this question.

Currently I've one method that completes a job:

for {
  var result string 
  var resultOK bool
  result, resultOK = worker1(job) 
  if resultOK {
     // go on to other things
  }
  ...
}

Suppose we now have another mechanism that may be able to finish this job faster - let's call it worker2. Note that in some cases worker1 may be faster.

What's the idiomatic way to launch these two workers and accept the result from the one which finishes first successfully?

I know of select mechanism, but it does not care for resultOK bool.

select {
case <- c1:
  // worker1 finished
case <- c2:
  // worker2 finished
case <- time.After(10 * time.Second):
  // we need to move on
}

Any advise would be much appreciated!


Solution

  • Usually this is solved by making each worker deliver the result on the same channel, and receive from the channel (once). Whoever is faster, its result will be used. It's also a good idea to signal other, slow workers this by e.g. using a context.Context (that their work is no longer needed, and they should abort as soon as possible).

    If you only receive once from the channel, care must be taken not to block the slow workers in case they end up finishing their work and trying to send the result: they may get blocked forever. So the channel should have sufficiently large buffer to not block the workers, or the workers should send using a select statement having a default branch to not get blocked in case the send operation cannot be executed.

    If the result produced by workers is not acceptable (e.g. an error occurred), the workers may of course decide not to send any results. Care must be taken again of course, because if all workers fail, no result would be delivered, so the receiving party could wait forever. This can be avoided by using a timeout, or making the workers send a result that indicates failure (which the receiver has to process, and in which case have to keep receiving until a good result is received or no more results are coming).