问题现象
当for 和 select结合使用时,break语言是无法跳出for之外的:
package main
import (
"fmt"
"time"
"context"
)
func main(){
d := time.Now().Add(3000 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
// Even though ctx will be expired, it is good practice to call its
// cancelation function in any case. Failure to do so may keep the
// context and its parent alive longer than necessary.
defer cancel()
for{
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
break
}
}
println("Done!")
}
上面的程序会造成死循环!
解决方案1:使用label(推荐)
package main
import (
"fmt"
"time"
"context"
)
func main(){
d := time.Now().Add(3000 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
// Even though ctx will be expired, it is good practice to call its
// cancelation function in any case. Failure to do so may keep the
// context and its parent alive longer than necessary.
defer cancel()
DONE:
for{
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
break DONE
}
}
println("Done!")
}
解决方案2:使用goto
package main
import (
"fmt"
"time"
"context"
)
func main(){
d := time.Now().Add(3000 * time.Millisecond)
ctx, cancel := context.WithDeadline(context.Background(), d)
// Even though ctx will be expired, it is good practice to call its
// cancelation function in any case. Failure to do so may keep the
// context and its parent alive longer than necessary.
defer cancel()
for{
select {
case <-time.After(1 * time.Second):
fmt.Println("overslept")
case <-ctx.Done():
fmt.Println(ctx.Err())
goto DONE
}
}
DONE:println("Done!")
}