在 Golang 中使用上下文超时停止 运行 函数
Stopping running function using context timeout in Golang
我想利用 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
实际:
实际发生的是循环保持 运行ning 直到完成,即使上下文遇到超时并且 select 侦听器在 <-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 的能力(有关详细信息,请参阅 )。 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")
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
注意:你是否看到打印出的"No: 3"
可能发生也可能不发生,因为任何迭代都需要1秒,超时是3秒= 3 *迭代延迟,所以无论是先发生超时还是第4次迭代开始首先是“活泼”。如果将超时减少到 2900 毫秒,将不会打印 "No: 3"
。
我想利用 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
实际:
实际发生的是循环保持 运行ning 直到完成,即使上下文遇到超时并且 select 侦听器在 <-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")
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
注意:你是否看到打印出的"No: 3"
可能发生也可能不发生,因为任何迭代都需要1秒,超时是3秒= 3 *迭代延迟,所以无论是先发生超时还是第4次迭代开始首先是“活泼”。如果将超时减少到 2900 毫秒,将不会打印 "No: 3"
。