I'm following this post to parallelise my app. I need to tailor this code:
func sq(done <-chan struct{}, in <-chan int) <-chan int {
out := make(chan int)
go func() {
defer close(out)
for n := range in {
select {
case out <- n * n:
case <-done:
return
}
}
}()
return out
}
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. Does select
just take the first true
case? Could it be rewritten:
for n := range in {
select {
case n:
out <- n * n
case <-done:
return
}
}
Anyway, I need to replace the line case out <- n * n:
with a function call. I've changed it to the following:
out := make(chan structs.Ticket)
go func() {
defer close(out)
for url := range inputChannel {
select {
case url:
data, err := GetData(url)
fmt.Println("Got error: ", err)
out <- data
case <-done:
return
}
}
}()
return out
It looks like this will compile (I can't compile it yet), but because it's not simple to debug parallel code I wanted to check that using case url
was the right way to select on a channel in a range
. Is this right?
Update
OK I've removed the remaining issues with my code, and now when I try to compile I get the error messages:
url evaluated but not used
select case must be receive, send or assign recv
Being in a range
or not doesn't have any impact on what select
is doing here.
No, select
doesn'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.