golang: context的应用
一,什么是context?
1,context是什么?
context 主要用来在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等。
2)传递取消信号(主动取消、时限/超时自动取消) !!!
context.Context 类型的值可以协调多个 groutine 中的代码执行“取消”操作,并且可以存储键值对。
最重要的是它是并发安全的。
与它协作的 API 都可以由外部控制执行“取消”操作,例如:取消一个 HTTP 请求的执行。
在Go 里,我们不能直接杀死协程,协程的关闭一般会用 channel+select 方式来控制。
但是在某些场景下,例如处理一个请求衍生了很多协程,这些协程之间是相互关联的:
需要共享一些全局变量、有共同的 deadline 等,而且可以同时被关闭。
再用 channel+select 就会比较麻烦,这时就可以通过 context 来实现。
简单的说context 用来解决 goroutine 之间退出通知、 元数据传递的功能。
二,context的应用
1,创建根context的两个方法:
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
func Background() Context {
return background
}
func TODO() Context {
return todo
}
2,创建子context的四个方法:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
func WithValue(parent Context, key, val interface{}) Context
3,例子:
两层context
rootCtx := context.Background()
childCtx := context.WithValue(rootCtx, "request_Id", "seekload")
三层context
rootCtx := context.Background()
childCtx := context.WithValue(rootCtx, "request_Id", "seekload")
childOfChildCtx, cancelFunc := context.WithCancel(childCtx)
四层context
rootCtx := context.Background()
childCtx1 := context.WithValue(rootCtx, "request_Id", "seekload")
childCtx2, cancelFunc := context.WithCancel(childCtx1)
childCtx3 := context.WithValue(rootCtx, "user_Id", "user_100")
三,context的使用例子:
1,context.WithCancel() 用于取消信号
func main() {
ctx := context.Background() //创建根context
cancelCtx, cancelFunc := context.WithCancel(ctx) //基于根创建第二层context对象,传入协程中
go task(cancelCtx)
time.Sleep(time.Second * 3)
cancelFunc() // 可以在父级对创建的子context发起取消 context(即结束协程)
time.Sleep(time.Second * 1) // 延时等待协程退出
fmt.Println("number of goroutine: ",runtime.NumGoroutine()) // 协程数量
}
func task(ctx context.Context) {
i := 1
for {
select {
case <-ctx.Done(): // 接收取消信号
fmt.Println("Gracefully exit")
fmt.Println(ctx.Err()) // 取消原因
return
default:
fmt.Println(i)
time.Sleep(time.Second * 1)
i++
}
}
}
2, context.WithValue() 可以在 goroutine 之间传递一些数据
func main() {
helloWorldHandler := http.HandlerFunc(HelloWorld)
http.Handle("/hello", inejctRequestId(helloWorldHandler))
http.ListenAndServe(":8080", nil)
}
func HelloWorld(w http.ResponseWriter, r *http.Request) {
requestId := ""
if m := r.Context().Value("requestId"); m != nil {
if value, ok := m.(string); ok {
requestId = value
}
}
w.Header().Add("requestId", requestId)
w.Write([]byte("Hello, world"))
}
func inejctRequestId(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
requestId := uuid.New().String()
ctx := context.WithValue(r.Context(), "requestId", requestId)
req := r.WithContext(ctx)
next.ServeHTTP(w, req)
})
}
3,context.WithTimeout() 可以设置一个超时时间,过期之后 channel done 会自动关闭,context 会被取消;
超时之前可以调用取消函数手动取消 context
func main() {
ctx := context.Background()
cancelCtx, cancel := context.WithTimeout(ctx, time.Second*3)
defer cancel()
go task(cancelCtx)
time.Sleep(time.Second * 4)
}
func task(ctx context.Context) {
i := 1
for {
select {
case <-ctx.Done():
fmt.Println("Gracefully exit")
fmt.Println(ctx.Err())
return
default:
fmt.Println(i)
time.Sleep(time.Second * 1)
i++
}
}
}
4, context.WithDeadline() 设置一个将来的时间点作为截止时间,时间到了之后,channel done 会自动关闭,context 会被取消;
还未到截止时间可以调用取消函数手动取消 context
func main() {
ctx := context.Background()
cancelCtx, cancel := context.WithDeadline(ctx, time.Now().Add(time.Second*3))
defer cancel()
go task(cancelCtx)
time.Sleep(time.Second * 4) // 延时,等待 task() 正常退出
}
func task(ctx context.Context) {
i := 1
for {
select {
case <-ctx.Done():
fmt.Println("Gracefully exit")
fmt.Println(ctx.Err())
return
default:
fmt.Println(i)
time.Sleep(time.Second * 1)
i++
}
}
}
四,参考来源
参考: https://www.jianshu.com/p/d4c0cb65374f
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
2023-02-09 flutter:使用listview之二:下拉刷新(flutter 3.7.0)
2023-02-09 macos安装uni-app开发环境(hbuilderx 3.6.18 / macos12.4)