Here is an example:
package main
import (
"fmt"
"time"
)
func main() {
ch := make(chan int)
for i := 0; i < 5; i++ {
time.Sleep(time.Millisecond)
go func(i int) {
for {
n := <-ch
fmt.Printf("Goroutine %d got %d\n", i, n)
}
}(i)
}
for i := 0; i < 20; i++ {
time.Sleep(time.Millisecond)
ch <- i
}
time.Sleep(time.Millisecond)
}
After the first loop, we have 5 goroutines that are waiting for messages from the channel. Then, we have the second loop. My expectations were that messages would be delivered to the random goroutines. Unfortunately, the output is always the same:
Goroutine 0 got 0
Goroutine 1 got 1
Goroutine 2 got 2
Goroutine 3 got 3
Goroutine 4 got 4
Goroutine 0 got 5
Goroutine 1 got 6
Goroutine 2 got 7
Goroutine 3 got 8
Goroutine 4 got 9
Goroutine 0 got 10
Goroutine 1 got 11
Goroutine 2 got 12
Goroutine 3 got 13
Goroutine 4 got 14
Goroutine 0 got 15
Goroutine 1 got 16
Goroutine 2 got 17
Goroutine 3 got 18
Goroutine 4 got 19
The delivery order, in this case, is first-come-first-got. Is it documented?
How can I change the behavior and deliver each message to a random goroutine?
Yes, in The Go Programming Language Specification.
AFAIK there is no way to alter the channel implementation. Simplest option would be to randomize your channel input.
However, the apparent neat order is only there because you're sleeping. Sleep in concurrent code is generally a bad sign. There's no way to predict how long each operation will take, so you wind up with either conservatively long sleeps leading to inefficient code, or sleeps that are sometimes too short leading to hard to debug errors.
There's no need to sleep when working with channels. If you try to send to a channel which has no room, the send will block. If you try to receive from a channel with nothing in it, the receive will block.
If you remove the sleeps and let Go operate concurrently, the nice neat order will go away. Instead, use channel buffering and sync.WaitGroup to coordinate.
Demonstration.
Now that we're allowing everything to operate concurrently, the order of processing will not exactly be random, but also won't be quite so ordered as each goroutine reads from the channel as fast as they can. Here is one possible output, it will vary from run to run.
In this case the first 5 reads from the channel were...
Then 4 finished its loop first and read 5 from the channel. And so on.
To better understand the code above, I recommend reading Go By Example starting at Goroutines and continuing on until WaitGroups.