我是 Golang 的新手,当我学习 golang 的上下文部分时,我WithCancel有些困惑。WithTimeout
显示代码。
package main
import (
"context"
"fmt"
"time"
)
func someHandler() {
//ctx, cancel := context.WithCancel(context.Background())
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
go doSth(ctx)
time.Sleep(3 * time.Second)
cancel()
}
func doSth(ctx context.Context) {
var i = 1
for {
time.Sleep(1 * time.Second)
select {
case <-ctx.Done():
fmt.Println("done")
return
default:
fmt.Printf("work %d seconds: \n", i)
}
i++
}
}
func main() {
fmt.Println("start...")
someHandler()
fmt.Println("end.")
}
Run Code Online (Sandbox Code Playgroud)
结果:
// when use WithCancel
//
start...
work 1 seconds:
work 2 seconds:
end.
// when use WithTimeout
start...
work 1 seconds:
done
end.
Run Code Online (Sandbox Code Playgroud)
done我的问题是:为什么我使用时不打印“ ” withCancel,但withTimeout打印它?
Parikshit Agnihotry的“理解 golang 中的上下文包” 提到:
context.WithCancel(parent Context) (ctx Context, cancel CancelFunc)此函数创建一个从传入的父上下文派生的新上下文。
父上下文可以是后台上下文或传递到函数中的上下文。这将返回派生上下文和取消函数。
只有创建此上下文的函数才应调用取消函数来取消此上下文。
如果您愿意,您可以传递取消函数,但是,强烈不建议这样做。这可能导致取消的调用者没有意识到取消上下文可能对下游产生什么影响。可能还有由此派生的其他上下文,这可能会导致程序以意外的方式运行。简而言之,永远不要绕过取消函数。Run Code Online (Sandbox Code Playgroud)ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2 * time.Second))
context.WithDeadline(parent Context, d time.Time) (ctx Context, cancel CancelFunc)此函数从其父级返回派生上下文,当超过截止日期或调用取消函数时,该上下文将被取消。
例如,您可以创建一个将在未来某个时间自动取消的上下文,并将其传递到子函数中。
当该上下文因截止日期到期而被取消时,所有获得该上下文的函数都会收到通知停止工作并返回。
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2 * time.Second))
Run Code Online (Sandbox Code Playgroud)
context.WithTimeout(parent Context, timeout time.Duration) (ctx Context, cancel CancelFunc)该功能类似于
context.WithDeadline.
不同之处在于它以持续时间而不是时间对象作为输入。
此函数返回一个派生上下文,如果调用取消函数或超过超时持续时间,该上下文将被取消。Run Code Online (Sandbox Code Playgroud)ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2 * time.Second))
为什么在使用 withCancel 时不打印“完成”,但使用 withTimeout 却打印“完成”
可能是因为 Go 程序在 goroutine 有时间确认“完成”部分之前就已经退出了。