Leo Houer
Leo Houer

Reputation: 347

Multiple receivers on a single channel. Who gets the data?

Unbuffered channels block receivers until data is available on the channel. It's not clear to me how this blocking behaves with multiple receivers on the same channel (say when using goroutines). I am sure they would all block as long as there is no data sent on that channel.
But what happens once I send a single value to that channel? Which receiver/goroutine will get the data and therefore unblock? All of them? The first in line? Random?

Upvotes: 20

Views: 14709

Answers (3)

drlolly
drlolly

Reputation: 194

If the program is allowing multiple goroutines to receive on a single channel then the sender is broadcasting. Each receiver should be equally able to process the data. So it does not matter what mechanism the go runtime uses to decide which of the many goroutine receivers will run. But only ONE will run for each sent item if the channel is unbuffered.

See also: https://github.com/golang/go/issues/247, especially the commend by user josef.svenningsson:

If there is no specified order then the implementation is free to starve a process completely, something which I think no-one would be happy with. Some kind of fairness guarantees are crucial to have in order to make sure that all goroutines can have a go at evaluating. So, this isn't an issue about being able to control in what order things are happening. My concern is that some goroutine may never get the chance to do its job if the order among receivers is undefined.

Upvotes: 1

9072997
9072997

Reputation: 978

There have been some discussion about this

But what is established in the Go Memory Model is that it will be at most one of them.

Each send on a particular channel is matched to a corresponding receive from that channel, usually in a different goroutine.

That isn't as clear cut as I would like, but later down they give this example of a semaphore implementation

var limit = make(chan int, 3)

func main() {
    for _, w := range work {
        go func(w func()) {
            limit <- 1
            w()
            // if it were possible for more than one channel to receive
            // from a single send, it would be possible for this to release
            // more than one "lock", making it an invalid semaphore
            // implementation
            <-limit
        }(w)
    }
    select{}
}

Upvotes: 0

Stephan Dollberg
Stephan Dollberg

Reputation: 34608

A single random (non-deterministic) one will receive it.

See the language spec:

Execution of a "select" statement proceeds in several steps:

  1. For all the cases in the statement, the channel operands of receive operations and the channel and right-hand-side expressions of send statements are evaluated exactly once, in source order, upon entering the "select" statement. The result is a set of channels to receive from or send to, and the corresponding values to send. Any side effects in that evaluation will occur irrespective of which (if any) communication operation is selected to proceed. Expressions on the left-hand side of a RecvStmt with a short variable declaration or assignment are not yet evaluated.
  2. If one or more of the communications can proceed, a single one that can proceed is chosen via a uniform pseudo-random selection. Otherwise, if there is a default case, that case is chosen. If there is no default case, the "select" statement blocks until at least one of the communications can proceed.
  3. Unless the selected case is the default case, the respective communication operation is executed.
  4. If the selected case is a RecvStmt with a short variable declaration or an assignment, the left-hand side expressions are evaluated and the received value (or values) are assigned.
  5. The statement list of the selected case is executed.

Upvotes: 18

Related Questions