go context剖析之使用技巧
context背景
因为goroutine,go的并发非常方便,但是这也带来了另外一个问题,当我们进行一个耗时的异步操作时,如何在约定的时间内终止该操作并返回一个自定义的结果?这也是大家常说的我们如何去终止一个goroutine(因为goroutine不同于os线程,没有主动interrupt机制),这里就轮到今天的主角context登场了。
context源于google,于1.7版本加入标准库,按照官方文档的说法,它是一个请求的全局上下文,携带了截止时间、手动取消等信号,并包含一个并发安全的map用于携带数据。context的API比较简单,接下来我会在具体的使用场景中进行介绍。
使用场景一: 请求链路传值
一般来说,我们的根context会在请求的入口处构造如下
ctx := context.Background()
复制代码
如果拿捏不准是否需要一个全局的context,可以使用下面这个函数构造
ctx := context.TODO()
复制代码
但是不可以为nil。
传值使用方式如下
package mainimport ("context""fmt"
)func func1(ctx context.Context) {ctx = context.WithValue(ctx, "k1", "v1")func2(ctx)
}
func func2(ctx context.Context) {fmt.Println(ctx.Value("k1").(string))
}func main() {ctx := context.Background()func1(ctx)
}
复制代码
我们在func1通过WithValue(parent Context, key, val interface{}) Context,赋值k1为v1,在其下层函数func2通过ctx.Value(key interface{}) interface{}获取k1的值,比较简单。这里有个疑问,如果我是在func2里赋值,在func1里面能够拿到这个值吗?答案是不能,context只能自上而下携带值,这个是要注意的一点。
使用场景二: 取消耗时操作,及时释放资源
可以考虑这样一个问题,如果没有context包,我们如何取消一个耗时操作呢?我这里模拟了两种写法
- 网络交互场景,经常通过SetReadDeadline、SetWriteDeadline、SetDeadline进行超时取消
timeout := 10 * time.Second
t = time.Now().Add(timeout)
conn.SetDeadline(t)
复制代码
- 耗时操作场景,通过select模拟
package mainimport ("errors""fmt""time"
)func func1() error {respC := make(chan int)// 处理逻辑go func() {time.Sleep(time.Second * 3)respC <- 10}()// 超时逻辑select {case r := <-respC:fmt.Printf("Resp: %d\n", r)return nilcase <-time.After(time.Second * 2):fmt.Println("catch timeout")return errors.New("timeout")}
}func main() {err := func1()fmt.Printf("func1 error: %v\n", err)
}
复制代码
以上两种方式在工程实践中也会经常用到,下面我们来看下如何使用context进行主动取消、超时取消以及存在多个timeout时如何处理
- 主动取消
package mainimport ("context""errors""fmt""sync""time"
)func func1(ctx context.Context, wg *sync.WaitGroup) error {defer wg.Done()respC := make(chan int)// 处理逻辑go func() {time.Sleep(time.Second * 5)respC <- 10}()// 取消机制select {case <-ctx.Done():fmt.Println("cancel")return errors.New("cancel")case r := <-respC:fmt.Println(r)return nil}
}func main() {wg := new(sync.WaitGroup)ctx, cancel := context.WithCancel(context.Background())wg.Add(1)go func1(ctx, wg)time.Sleep(time.Second * 2)// 触发取消cancel()// 等待goroutine退出wg.Wait()
}
复制代码
- 超时取消
package mainimport ("context""fmt""time"
)func func1(ctx context.Context) {hctx, hcancel := context.WithTimeout(ctx, time.Second*4)defer hcancel()resp := make(chan struct{}, 1)// 处理逻辑go func() {// 处理耗时time.Sleep(time.Second * 10)resp <- struct{}{}}()// 超时机制select {// case <-ctx.Done():// fmt.Println("ctx timeout")// fmt.Println(ctx.Err())case <-hctx.Done():fmt.Println("hctx timeout")fmt.Println(hctx.Err())case v := <-resp:fmt.Println("test2 function handle done")fmt.Printf("result: %v\n", v)}fmt.Println("test2 finish")return}func main() {ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)defer cancel()func1(ctx)
}
复制代码
对于多个超时时间的处理,可以把上述超时取消例子中的注释打开,会观察到,当处理两个ctx时,时间短的会优先触发,这种情况下,如果只判定一个context的Done()也是可以的,但是一定要保证调用到两个cancel函数
注意事项
- context只能自顶向下传值,反之则不可以。
- 如果有cancel,一定要保证调用,否则会造成资源泄露,比如timer泄露。
- context一定不能为nil,如果不确定,可以使用context.TODO()生成一个empty的context。
以上是context剖析的上篇,主要从使用层面,让大家有一个直观的认识,这样在工程中可以进行灵活的使用,接下来会从源码层面进行剖析。
参考资料
golang官方包
Go Concurrency Patterns: Context
etcd客户端超时处理示例代码
转载于:https://juejin.im/post/5c127a6fe51d453db84fc9c0
go context剖析之使用技巧相关推荐
- 计算机二级vb选择题分值,计算机二级VB考试的考试分值和考试题型剖析及解题技巧...
前言 大家好!欢迎来到多智教育,我是授课教师李老师. 每年的全国计算机等级考试一直是让很多同学头疼的问题,怎样才能顺利通过考试呢?综合分析历次考试试卷,我发现其实每次考试难度波动很小.题型类似或一样的 ...
- 26 JSX深度剖析与使用技巧
React对JSX的处理 React.createElement有三个参数:标签类型,属性集合,子元素 JSX其实是React.createElement函数调用的语法糖 JSX → 编译 → Rea ...
- Golang Context 详细原理和使用技巧
文章目录 Golang Context 详细原理和使用技巧 Context 背景 和 适用场景 Context 的背景 Context 的功能和目的 Context 的基本使用 Context 的同步 ...
- android获取context的方法,Android编程获取全局Context的方法
Android编程获取全局Context的方法 本文实例讲述了Android编程获取全局Context的方法.分享给大家供大家参考,具体如下: 有时,在处理业务逻辑的时候,需要Context对象,但在 ...
- Struts2基础知识(三)
本文主要包括以下内容 OGNL表达式 标签 防止表单重复提交 使用第三方插件 tomcat启动时struts2容器做的事 OGNL表达式 OGNL是Object Graphic Navigation ...
- 大厂产品经理是如何做好用数据驱动业务增长的?
互联网下半场,随着市场的成熟和用人要求愈发严格,越来越多产品经理面临更艰难的职场困境. 产品经理被唱衰也成了常事,在网上随手一搜都是"未来5年产品经理必死" "转行产品经 ...
- 国家二级计算机vb考试题型,2015全国计算机等级考试二级VB题型分析
2015全国计算机等级考试二级VB题型分析 考试方式 1. 笔试:90分钟,满分100分,其中含公共基础知识部分的30分. 2. 上机操作:90分钟,满分100分. 上机操作包括: (1) 基本操作. ...
- iOS--开发从入门到精通
前言: 从事iOS开发已有几个年头,平时对于iOS开发的知识积累都比较碎片化,为了更好的掌握开发技能, 索性整理iOS开发的知识体系,以便于后面进阶成iOS高级开发工程师. 一.iOS开发基础 开发设 ...
- Akka查询设备组《fourteen》译
加入以下依赖到项目中: 介绍: 到目前为止,我们看到的会话模式很简单,因为它们要求Actor保持很少或没有状态. 特别: 设备actor返回一个读数,不需要更改状态. 记录温度,更新单个字段. 设备组 ...
最新文章
- 数字翻滚效果 HTML,js数字翻动效果 数字翻成中文怎么翻
- linux基础——linux进程间通信(IPC)机制总结
- rabbitmq学习:
- unity3d 求两个点长度_三年级上册求组合图形周长专项练习,附答案
- centos安装rpm格式jdk
- 拓端tecdat|Mac系统R语言升级后无法加载包报错 package or namespace load failed in dyn.load(file, DLLpath = DLLpath,
- Java Web - 笔记(1)
- 视频教程-CCNA自学视频课程专题四:CCNA认证重点难点解析3(扩展篇)-思科认证
- Java jar 如何防止被反编译
- 小米 Notebook Air 2016 13.3黑苹果efi引导文件
- pid上限问题,linux进程pid达到最大值,linux进程数最大值修改方法
- 大数据高级开发工程师——Spark学习笔记(6)
- seosem是什么意思?
- 相机标定与3D重建(0)标定板说明
- 恢复重装系统后的EFS加密文件
- Ubuntu Github基本使用方法
- 脚本:批量复制微信后台用户消息
- 圣诞树Easyx绘图
- threejs辉光通道01(UnrealBloomPass layers)
- Jmeter 的 vars 和 props 用法