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剖析之使用技巧相关推荐

  1. 计算机二级vb选择题分值,计算机二级VB考试的考试分值和考试题型剖析及解题技巧...

    前言 大家好!欢迎来到多智教育,我是授课教师李老师. 每年的全国计算机等级考试一直是让很多同学头疼的问题,怎样才能顺利通过考试呢?综合分析历次考试试卷,我发现其实每次考试难度波动很小.题型类似或一样的 ...

  2. 26 JSX深度剖析与使用技巧

    React对JSX的处理 React.createElement有三个参数:标签类型,属性集合,子元素 JSX其实是React.createElement函数调用的语法糖 JSX → 编译 → Rea ...

  3. Golang Context 详细原理和使用技巧

    文章目录 Golang Context 详细原理和使用技巧 Context 背景 和 适用场景 Context 的背景 Context 的功能和目的 Context 的基本使用 Context 的同步 ...

  4. android获取context的方法,Android编程获取全局Context的方法

    Android编程获取全局Context的方法 本文实例讲述了Android编程获取全局Context的方法.分享给大家供大家参考,具体如下: 有时,在处理业务逻辑的时候,需要Context对象,但在 ...

  5. Struts2基础知识(三)

    本文主要包括以下内容 OGNL表达式 标签 防止表单重复提交 使用第三方插件 tomcat启动时struts2容器做的事 OGNL表达式 OGNL是Object Graphic Navigation ...

  6. 大厂产品经理是如何做好用数据驱动业务增长的?

    互联网下半场,随着市场的成熟和用人要求愈发严格,越来越多产品经理面临更艰难的职场困境. 产品经理被唱衰也成了常事,在网上随手一搜都是"未来5年产品经理必死" "转行产品经 ...

  7. 国家二级计算机vb考试题型,2015全国计算机等级考试二级VB题型分析

    2015全国计算机等级考试二级VB题型分析 考试方式 1. 笔试:90分钟,满分100分,其中含公共基础知识部分的30分. 2. 上机操作:90分钟,满分100分. 上机操作包括: (1) 基本操作. ...

  8. iOS--开发从入门到精通

    前言: 从事iOS开发已有几个年头,平时对于iOS开发的知识积累都比较碎片化,为了更好的掌握开发技能, 索性整理iOS开发的知识体系,以便于后面进阶成iOS高级开发工程师. 一.iOS开发基础 开发设 ...

  9. Akka查询设备组《fourteen》译

    加入以下依赖到项目中: 介绍: 到目前为止,我们看到的会话模式很简单,因为它们要求Actor保持很少或没有状态. 特别: 设备actor返回一个读数,不需要更改状态. 记录温度,更新单个字段. 设备组 ...

最新文章

  1. 数字翻滚效果 HTML,js数字翻动效果 数字翻成中文怎么翻
  2. linux基础——linux进程间通信(IPC)机制总结
  3. rabbitmq学习:
  4. unity3d 求两个点长度_三年级上册求组合图形周长专项练习,附答案
  5. centos安装rpm格式jdk
  6. 拓端tecdat|Mac系统R语言升级后无法加载包报错 package or namespace load failed in dyn.load(file, DLLpath = DLLpath,
  7. Java Web - 笔记(1)
  8. 视频教程-CCNA自学视频课程专题四:CCNA认证重点难点解析3(扩展篇)-思科认证
  9. Java jar 如何防止被反编译
  10. 小米 Notebook Air 2016 13.3黑苹果efi引导文件
  11. pid上限问题,linux进程pid达到最大值,linux进程数最大值修改方法
  12. 大数据高级开发工程师——Spark学习笔记(6)
  13. seosem是什么意思?
  14. 相机标定与3D重建(0)标定板说明
  15. 恢复重装系统后的EFS加密文件
  16. Ubuntu Github基本使用方法
  17. 脚本:批量复制微信后台用户消息
  18. 圣诞树Easyx绘图
  19. threejs辉光通道01(UnrealBloomPass layers)
  20. Jmeter 的 vars 和 props 用法

热门文章

  1. win7下搭建手动转码服务器的安装配置tomcat、java、ffmpeg、hy_changsha、FTP
  2. Python - while语句和if语句 的 用法 及 代码
  3. NYOJ-199 无线网络覆盖
  4. 基于SSM实现旅游网站管理系统
  5. IndexError: too many indices for array
  6. jupyter和matlab的配置
  7. JS基础篇之作用域、执行上下文、this、闭包
  8. C++ pair的使用
  9. 第7章 jQuery中的事件与动画
  10. 基于微信的图片放大预览