Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Concurrent send/receive go channel

I have a go channel called queue with let's say 100 as the buffer size. Many go routines can send data to this channel, and another go routine is sitting there to receive data from this channel. This is a long lasting process, meaning the channel is acting like a pipeline absorbing data from many ends and sinking data to one end. I do something like this in the receiving go routine:

for {
    for data := range queue {
        sink(data)
    }
} 

Now my question is: what if some new data were sent to the channel buffer before the range loop is finished. Will the new data be available for the next range loop? Or they will be missed if concurrency is not taken into consideration in this case?

like image 479
Qian Chen Avatar asked Jan 08 '23 13:01

Qian Chen


2 Answers

You only need one for loop. From the spec on range expressions:

For channels, the iteration values produced are the successive values sent on the channel until the channel is closed. If the channel is nil, the range expression blocks forever.

In this case, the range loop is not acting like a regular range over, for example, a slice. Instead, when an item can be read from the channel, the loop body processes it. Therefore, your nested loops should be replaced with the following:

for data := range queue {
    sink(data)
}
like image 147
Tim Cooper Avatar answered Jan 15 '23 12:01

Tim Cooper


As @Tim said, you only need a single for, since range will emit values from the channel, until it is closed.

Overall, the pattern you describe is called fan-in. A example for a basic producer/consumer setup can be found here: http://play.golang.org/p/AhQ012Qpwj. The range loop runs in the consumer:

// consumer acts as fan in, signals when it is done.
func consumer(out chan string, done chan bool) {
    for value := range out {
        fmt.Println(value)
    }
    done <- true
}
like image 32
miku Avatar answered Jan 15 '23 12:01

miku