Reputation: 7787
I'm trying to use a select
in a loop to receive either a message or a timeout signal. If the timeout signal is received, the loop should abort:
package main
import ("fmt"; "time")
func main() {
done := time.After(1*time.Millisecond)
numbers := make(chan int)
go func() {for n:=0;; {numbers <- n; n++}}()
for {
select {
case <-done:
break
case num := <- numbers:
fmt.Println(num)
}
}
}
However, it doesn't seem to be stopping:
$ go run a.go
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[...]
3824
3825
[...]
Why? Am I using time.After
wrong?
Upvotes: 38
Views: 40722
Reputation: 4171
How about using some control variable to skip the loop? It's kind of hard or not so easy to understand with breaking label sometimes.
package main
import ("fmt"; "time")
func main() {
done := time.After(1*time.Millisecond)
numbers := make(chan int)
go func() {for n:=0;; {numbers <- n; n++}}()
completed := false
for !completed {
select {
case <-done:
completed = true
// no break needed here
case num := <- numbers:
fmt.Println(num)
}
}
}
Upvotes: 12
Reputation: 454
I have the following solution, by using a anonymous function.
func() {
for {
select {
case <-time.After(5 * time.Second):
if token := c.Connect(); token.Wait() && token.Error() != nil {
fmt.Println("connect err:", token.Error())
} else {
fmt.Println("breaking")
return
}
}
}
}()
Upvotes: 10
Reputation: 99234
The "Go" way for that kind of situations is to use labels and break on the label, for example:
L:
for {
select {
case <-done:
break L
case num := <- numbers:
fmt.Println(num)
}
}
Ref:
Upvotes: 35
Reputation: 4814
In your example code, a return
seems appropriate as Pat says, but for future reference you can use labels:
package main
import (
"fmt"
"time"
)
func main() {
done := time.After(1 * time.Millisecond)
numbers := make(chan int)
// Send to channel
go func() {
for n := 0; ; {
numbers <- n
n++
}
}()
readChannel:
for {
select {
case <-done:
break readChannel
case num := <-numbers:
fmt.Println(num)
}
}
// Additional logic...
fmt.Println("Howdy")
}
Upvotes: 13
Reputation: 906
The Go spec says:
A "break" statement terminates execution of the innermost "for", "switch", or "select" statement within the same function.
In your example you're just breaking out of the select statement. If you replace break
with a return
statement you will see that it's working.
Upvotes: 48