Unless there's another branch of the select, use the following:
Copyfor v := range ch {
// do some stuff
}
The code is simpler and easier to understand than the for/select presented in the question.
If you need to do the receive inside the loop for some reason, then use the following code:
Copy for {
// do some stuff
v, ok := <-ch
if !ok {
break
}
// do some other stuff
}
As a rule of thumb, single branch select statements should be avoided. A select with a single branch is functionally the same as the branch alone.
Answer from user5728991 on Stack OverflowUnless there's another branch of the select, use the following:
Copyfor v := range ch {
// do some stuff
}
The code is simpler and easier to understand than the for/select presented in the question.
If you need to do the receive inside the loop for some reason, then use the following code:
Copy for {
// do some stuff
v, ok := <-ch
if !ok {
break
}
// do some other stuff
}
As a rule of thumb, single branch select statements should be avoided. A select with a single branch is functionally the same as the branch alone.
If you are simply awaiting on a done channel where you do not need the value returned, then you can drop the for loop entirely as the chan will block. Eg
Copy// Verbose
go func() {
for {
select {
case <-blah.Context.Done():
// Cleanup/Close
return
}
}
}()
// Simplified
go func() {
<-blah.Context.Done():
// Cleanup/Close (No return required either)
}()
Question about ranging over channels
goroutine - Selecting inside range over go channel - Stack Overflow
Question: multiple channels + select vs one channel of interface
Beginner question about channels
Videos
Hey all! I am writing a function that will read messages sent to a channel and used like this:
go readMessages(messenger)
Where messenger is the channel of string messages.
I am confused about the difference between this:
func readMessages(messenger <-chan string) {
for {
select {
case msg := <-messenger:
fmt.Println(msg)
}
}
}and this:
func readMessages(messenger <-chan string) {
for msg := range messenger {
fmt.Println(msg)
}
}Are they equivalent? Or Should I prefer one over the other and why?
Being in a
rangeor not doesn't have any impact on whatselectis doing here.No,
selectdoesn't take the first true expression... it doesn't take expressions at all. The only things that can appear as the cases of an expression are channel sends, channel receives, and assignments with channel receives on their right side.select { case out <- n * n: case <-done: return }
says "if sending on out is possible (i.e. it has remaining capacity or an active reader), then send the value n * n to it and continue. If receiving from done is possible, return from the function. If both are possible, choose one at random and do it. If neither is possible, wait until one of them becomes possible." (See Select Statements in the spec).
If the value you want to send needs to be computed (and it's too complex to put on the right hand side of the channel send), simply do it before the select. The spec makes it clear that all of the expressions in send statements in a select are computed ahead of time anyway, so nothing is lost.
I don't fully understand the line
case out <- n * n:. I can see it's saying that if there's a value for n, then square it and send it down the channel, but I don't understand why.
That's not correct. case out <- n * n checks to see if out is ready to read, and sends n * n to out if it is. Unless done is also ready.
select is used when you have multiple channels to talk to. Whichever channel is ready, it will do that case. If multiple channels are ready, it will select one at random.
select {
case out <- n * n:
case <-done:
return
}
}
This will select over out and done. If either is ready to proceed, ie. out is ready to read or there's something to read from done, it will pick one of those cases. The order is random, so it is possible to send more down out even if there's something to be read from done.
This pattern is used to shut down infinite goroutines. If you stop reading from its output channel, it won't do any more work, but it will hang around in memory. So by passing a value to done you can tell the goroutine to shut down.
UPDATE: In your original case, where the goroutine is looping over an input channel and sending output, done is an unnecessary complication. Once the input channel is closed, the function will return.
func sq(in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
out <- n * n
}
}()
return out
}
func main() {
in := make(chan int)
out := sq(in)
for _,i := range []int{1,2,3,4} {
in <- i
fmt.Println(<-out)
}
// The `range` inside the goroutine from sq() will exit,
// and the goroutine will return.
close(in)
}
If it just spat out an ever increasing set of squares, then done would be necessary inside an infinite loop.
func sq(done chan bool) <-chan int {
out := make(chan int)
go func() {
defer close(out)
n := 0
for {
select {
case <-done:
return
case out<-n*n:
n++
}
}
}()
return out
}
func main() {
done := make(chan bool)
out := sq(done)
for range []int{1,2,3,4} {
fmt.Println(<-out)
}
// The switch in the goroutine will be able to read
// from done (out's buffer being already full) and return.
done <- true
}
Suppose you have a long-running goroutine that accepts different operations. In my case, it is a routine that listens for different events and reacts to them. I am using a single coroutine because the events are not independent and the reactions depend on an internal state (and I can avoid locks) and it's a pretty short code to have it in a single function.
My question, I can create a channel for each operation and use select in the goroutine or use a single channel of a common interface and dispatch by message type.
The only advantage I see in the single channel approach is that messages are dispatched on the order they are received, which can be important on some scenarios, but in my case it is not.
Do you have any experience or opinion about which approach is better?
Thanks!
Lately I've been learning go and I'm really liking it so far. I think Go fits the needs of a JavaScript programmer that wants to go lower level but not as low as c/c++.Currently I'm using Go by example for learning purposes.
I was learning channels and it's taking me a while to wrap my head around it.
I'm not understanding why the following code with channels works they way it does.
Part 1 taken from Range over channels section
Part 2 taken from Worker pools section
I modified the Part 1 and instead of closing the channel before iterating over it, I closed it after the iteration, resulting in a "all goroutines are asleep - deadlock!" error message in runtime. It looks like you cant iterate over a channel that's not closed. Fair enough.
Then I stumbled upon worker pools and in the example the worker is iterating over jobs channel even though its not closed?
Clearly my understanding of channels is not correct.
Why is Part 2 working well and the modified version of Part 1 (iterate over a channel that's not closed) is not?
Thank you in advance