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)
}()
goroutine - Selecting inside range over go channel - Stack Overflow
Question about ranging over channels
Question: multiple channels + select vs one channel of interface
go - select with single case blocks, adding default: unblocks - Stack Overflow
Videos
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
}
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?
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!
1- When you are dealing with one channel, it is OK to use for,
consider this working code ( The Go Playground ):
package main
import "fmt"
func main() {
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
for range ch {
}
fmt.Println("Done.")
}
This will empty the channel.
Note: you should close the channel or you should use break statement to finish that loop.
2- When you are dealing with more channels you may use select, like this ( The Go Playground ):
for {
select {
case <-pause:
fmt.Println("pause")
select {
case <-play:
fmt.Println("play")
case <-quit:
wg.Done()
return
}
case <-quit:
wg.Done()
return
default:
work()
}
}
3- Using nil and closed channel ( The Go Playground ):
package main
import "fmt"
func main() {
var quit chan struct{} // nil
select {
case <-quit:
fmt.Println("1")
default:
fmt.Println("2") // This runs
}
quit = make(chan struct{}, 1)
select {
case <-quit:
fmt.Println("10")
default:
fmt.Println("20") // This runs
}
quit <- struct{}{} // send
select {
case <-quit:
fmt.Println("100") // This runs
default:
fmt.Println("200")
}
close(quit)
select {
case <-quit:
fmt.Println("1000") // This runs
default:
fmt.Println("2000")
}
select {
case <-quit:
fmt.Println("10000") // This runs
default:
fmt.Println("20000")
}
}
output:
2
20
100
1000
10000
Select statements
A "select" statement chooses which of a set of possible send or receive operations will proceed. It looks similar to a "switch" statement but with the cases all referring to communication operations.
A case with a RecvStmt may assign the result of a RecvExpr to one or two variables, which may be declared using a short variable declaration. The RecvExpr must be a (possibly parenthesized) receive operation. There can be at most one default case and it may appear anywhere in the list of cases.
Execution of a "select" statement proceeds in several steps:
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. 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. Unless the selected case is the default case, the respective communication operation is executed. 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. The statement list of the selected case is executed. Since communication on nil channels can never proceed, a select with only nil channels and no default case blocks forever.
In your case, it seems that a simple loop would suffice:
for _ = range ch {
fmt.Println("drain")
}
Select is required, if you have multiple goroutines to handle. The tour has an example of range and close.
Another case for select would be idempotent channel closes: https://play.golang.org/p/_Ol42BvuuS.