user1663023
user1663023

Reputation:

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?

Upvotes: 4

Views: 489

Answers (2)

miku
miku

Reputation: 188194

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
}

Upvotes: 4

user142162
user142162

Reputation:

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)
}

Upvotes: 5

Related Questions