我想利用golang中的上下文来在超时时用于取消。
代码:
package main
import "fmt"
import "time"
import "context"
func F(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx,3*time.Second)
defer cancel()
for i:=0;i<10;i++ {
time.Sleep(1 * time.Second)
fmt.Println("No: ",i)
}
select {
case <-ctx.Done():
fmt.Println("TIME OUT")
cancel()
return ctx.Err()
default:
fmt.Println("ALL DONE")
return nil
}
}
func main() {
ctx := context.Background()
err := F(ctx)
if err != nil {
fmt.Println(err)
}else {
fmt.Println("Success")
}
}
期望:上面的代码应停止在计数器2
处运行循环,因为超时为3秒,而循环每次运行1秒。所以我希望这样:
No: 0
No: 1
No: 2
TIME OUT
context deadline exceeded
实际:实际发生的是,即使上下文遇到超时并且选择侦听器在<-ctx.Done()
上捕获到超时,循环仍将继续运行直到完成。这段代码显示:
No: 0
No: 1
No: 2
No: 3
No: 4
No: 5
No: 6
No: 7
No: 8
No: 9
TIME OUT
context deadline exceeded
在遇到超时后如何停止函数执行?
context.Context
只能中继发生超时或取消的消息。它无权实际停止任何goroutine。
您有一个循环,该循环无条件地迭代10次并打印出一些内容。并且您仅在循环后检查超时。
您必须将上下文检查移入循环:
func F(ctx context.Context) error {
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
for i := 0; i < 10; i++ {
select {
case <-ctx.Done():
fmt.Println("TIME OUT")
cancel()
return ctx.Err()
default:
time.Sleep(1 * time.Second)
fmt.Println("No: ", i)
}
}
fmt.Println("ALL DONE")
return nil
}
进行此更改后,输出将是(在Go Playground上尝试):
No: 0
No: 1
No: 2
No: 3
TIME OUT
context deadline exceeded