golang context使用小结
Go标准库中的context包,提供了goroutine之间的传递信息的机制,信号同步,除此之外还有超时(timeout)和取消(cancel)机制。概括起来,Context可以控制子goroutine的运行,超时控制的方法调用,可以取消的方法调用。
context核心数据结构
- Context interface
type Context interface {
Deadline() (deadline time.Time, ok bool)
// 返回这个Context被取消的截止时间,如果没有设置截止时间,ok的值返回的是false
Done() <-chan struct{}
// 返回一个只读的channel 一般用来监听context的取消 当context关闭后,Done()返回一个被关闭的管道,关闭的管道仍然是可读的,据此goroutine可以收到关闭请求,当context还未关闭时,Done()返回nil
Err() error
// 当context关闭后,Err()返回context的关闭原因 当context还未关闭时,Err()返回nil
Value(key any) any
// 返回此cxt中指定key对应的value 用于goroutine间传递信息
}
- 生产对应的结构体
context包提供了4个方法创建不同类型的context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) // CancelCtx 创建带有取消功能的Context
func WithDeadline(parent Context, d time.Time) (Context, CancelFunc) // DeadLineCtx 创建带有定时自动取消功能的Context
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) // TimeoutCtx 创建带有定时自动取消功能的Context
func WithValue(parent Context, key, val any) Context // ValueCtx 带有键值的context
- emptyCtx
type emptyCtx int // 是一个空的 context,本质上类型为一个整型 可以由 context.Background() 或 context.TODO() 获取
var (
background = new(emptyCtx)
todo = new(emptyCtx)
)
// context.Background() 和 context.TODO() 本质上没有什么区别 都用于创建一个默认的、无限期的上下文,只是用于不同场景下
// 通常被用于主函数、初始化以及测试中,作为一个顶层的context,也就是说一般我们创建的context都是基于Background
// 而TODO是在不确定使用什么context的时候才会使用
使用
1.WithCancel
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
go gOne(ctx, "任务一")
time.Sleep(time.Second * 10)
cancel()
time.Sleep(time.Second * 2)
fmt.Println("exit")
}
func gOne(ctx context.Context, name string) {
go gTwo(ctx, "任务二")
for {
select {
case <-ctx.Done():
fmt.Println(name + ":任务已停止")
return
case <-time.After(time.Second * 1):
fmt.Println(name + "任务执行中")
}
}
}
func gTwo(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name + ":任务已停止")
return
case <-time.After(time.Second * 2):
fmt.Println(name + "任务执行中")
}
}
}
2.WithDeadline WithTimeout
这两个方法本质是一样的 WithTimeout也是调用的WithDeadline方法
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) {
return WithDeadline(parent, time.Now().Add(timeout))
}
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, _ := context.WithTimeout(context.Background(), time.Second*5)
go gTimeOne(ctx, "任务一")
time.Sleep(10 * time.Second)
fmt.Println("exit")
}
func gTimeOne(ctx context.Context, name string) {
go gTimeTwo(ctx, "任务二")
for {
select {
case <-ctx.Done():
fmt.Println(name + ":任务已停止")
return
case <-time.After(time.Second * 1):
fmt.Println(name + "任务执行中")
}
}
}
func gTimeTwo(ctx context.Context, name string) {
for {
select {
case <-ctx.Done():
fmt.Println(name + ":任务已停止")
return
case <-time.After(time.Second * 2):
fmt.Println(name + "任务执行中")
}
}
}
3.WithValue
使用valueContext在协程之间共享数据
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx := context.WithValue(context.Background(), "param", "1234")
go gWork(ctx)
time.Sleep(time.Second * 5)
fmt.Println("exit")
}
func gWork(ctx context.Context) {
value := ctx.Value("param").(string)
fmt.Println(value)
}
由于valueCtx不具有Done() 相关方法的实现,一般是配合另几个方法使用
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx, cancel := context.WithCancel(context.Background())
valueCtx := context.WithValue(ctx, "param", "1234")
go gWork2(valueCtx)
time.Sleep(time.Second * 5)
cancel()
time.Sleep(time.Second * 10)
fmt.Println("exit")
}
func gWork2(ctx context.Context) {
value := ctx.Value("param").(string)
fmt.Println(value)
for {
select {
case <-ctx.Done():
fmt.Println("任务已停止")
return
case <-time.After(time.Second * 2):
fmt.Println("任务执行中")
}
}
}
gin中context的使用
gin接口超时处理
1.利用context.WithTimeout的特性去实现
// 入侵式
https://gist.github.com/montanaflynn/ef9e7b9cd21b355cfe8332b4f20163c1
// 非入侵式,无须修改原来代码(可能有bug)
https://vearne.cc/archives/39130
2.官方提供的插件
https://github.com/gin-contrib/timeout
grpc中context的使用
// 利用context做grpc超时处理
https://www.cnblogs.com/rickiyang/p/15049307.html
// grpc系列文章
https://zhuanlan.zhihu.com/p/612406500
// grpc超时传递原理
https://xiaomi-info.github.io/2019/12/30/grpc-deadline/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具