使用上下文来跳出循环
Use context to break out of a loop
考虑这个 (https://play.golang.org/p/zvDiwul9QR0):
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
for {
select {
case <-ctx.Done():
fmt.Println("Done")
break
default:
for {
fmt.Println("loop")
time.Sleep(500 * time.Millisecond)
}
}
}
}
所以这里的上下文 returns 是 2 秒后的“Done()”通道。我想抓住这个并取消我的无限循环。上面的代码示例没有这样做,它永远不会退出循环。
我怎样才能做到这一点?
上下文取消并不神奇——它们只是一种信号机制。要中止工作,您需要从您的 worker goroutine 监视 context
的状态:
for {
fmt.Println("loop")
select {
case <-time.After(500 * time.Millisecond):
case <-ctx.Done():
return
}
}
https://play.golang.org/p/L6-nDpo9chb
也正如 Eli 指出的那样,break
只会跳出 select 语句——因此您需要更精确的东西来跳出循环。重构为函数使 return
的任务中止更加直观。
根据评论跟进。我会像这样重构你的任务:
// any potentially blocking task should take a context
// style: context should be the first passed in parameter
func myTask(ctx context.Context, poll time.Duration) error {
for {
fmt.Println("loop")
select {
case <-time.After(poll):
case <-ctx.Done():
return ctx.Err()
}
}
}
考虑这个 (https://play.golang.org/p/zvDiwul9QR0):
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
for {
select {
case <-ctx.Done():
fmt.Println("Done")
break
default:
for {
fmt.Println("loop")
time.Sleep(500 * time.Millisecond)
}
}
}
}
所以这里的上下文 returns 是 2 秒后的“Done()”通道。我想抓住这个并取消我的无限循环。上面的代码示例没有这样做,它永远不会退出循环。
我怎样才能做到这一点?
上下文取消并不神奇——它们只是一种信号机制。要中止工作,您需要从您的 worker goroutine 监视 context
的状态:
for {
fmt.Println("loop")
select {
case <-time.After(500 * time.Millisecond):
case <-ctx.Done():
return
}
}
https://play.golang.org/p/L6-nDpo9chb
也正如 Eli 指出的那样,break
只会跳出 select 语句——因此您需要更精确的东西来跳出循环。重构为函数使 return
的任务中止更加直观。
根据评论跟进。我会像这样重构你的任务:
// any potentially blocking task should take a context
// style: context should be the first passed in parameter
func myTask(ctx context.Context, poll time.Duration) error {
for {
fmt.Println("loop")
select {
case <-time.After(poll):
case <-ctx.Done():
return ctx.Err()
}
}
}