Myrfy
Myrfy

Reputation: 675

how to wait on 2 channels and continue when they are both ready for read

Suppose I have 2 buffered channels, How can I wait for both of them, and only continue when both of the channel have at least one item in it?

It looks like assemble a machine with two parts, only when both part are at hand can I continue my work.

Both queue are empty, wait.
-------------------
|     |     |     |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------


Queue A has one element but Queue B empty, wait
-------------------
|     |     |  X  |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------


Queue A has two elements but Queue B empty, still wait
-------------------
|     |  Y  |  X  |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------


Both queue has item in it, consume one from each queue.
-------------------
|     |  Y  |  X  |   QUEUE A
-------------------

-------------------
|     |     |  Z  |   QUEUE B
-------------------


Now, Queue B empty again, wait ...
-------------------
|     |     |  Y  |   QUEUE A
-------------------

-------------------
|     |     |     |   QUEUE B
-------------------

Upvotes: 2

Views: 255

Answers (2)

icza
icza

Reputation: 418435

Receiving from 2 channels is not atomic. You can check the number of elements queued in a channel's buffer using the builtin len() function, but you can't do a 2-channel atomic receive.

Meaning by the time you receive a value from one channel, the other channel might not be ready to receive from (e.g. another goroutine might already have received from it).

If there is only one goroutine that consumes and processes these values, simply receive a value from both channels, it will block if a value is not ready (if channel is not ready to receive from):

v1 := <- ch1
v2 := <- ch2

// process v1 and v2

Also note that receiving also succeeds if the channel is closed.

Upvotes: 2

TehSphinX
TehSphinX

Reputation: 7440

How about something like this:

type Foo1 struct {}
type Foo2 struct {}

type Combination struct {
    foo1 *Foo1
    foo2 *Foo2
}

func mergeChan(chIn chan *Foo1, chIn2 chan *Foo2, chOut chan *Combination) {
    for foo1 := range chIn {
        chOut <- &Combination{
            foo1: foo1,
            foo2: <-chIn2,
        }
    }
}

Listening to chOut you would always receive combinations from both channels.

Upvotes: 0

Related Questions