Go Context包使用
来源:互联网 发布:pda软件开发 编辑:程序博客网 时间:2024/05/17 03:45
前言
做为go的使用者,大家应该都多多少少的见过Context包。可是因为我得懒惰都没有跳转进去好好看看,导致我对Context包理解并不深。写博客是一个很好的方式提醒自己不要懒惰,而且还能当成自己的笔记,平时翻一翻加深下记忆。
Context使用场景
目前总结两种使用场景:
1. 主动停止groutine
2. 传递数据
Context是什么?
Context直译为上下文,我们来看一下Context包中对它的说明,在go1.7之后已经添加到了标准库中,我们之间可以在/src/context中查看。
Context包中对Context的说明
英文水平不是太好就直译了过来,最近有在学习英文,遇到了很多优秀的人,真的是比你优秀的人比你还努力。又扯远了…
- 包context定义了Context类型,并包含deadlines(结束时间),cancelation signals(取消信号),和其他的请求api范围的值。
- 对服务器的请求应该创建一个Context,服务器发出的外向请求应该接受Context。链式的函数调用之间必须传递Context,随意的更换它使用一个导出Context使用WithCancel、WithDeadline、WithTimeout、WithValue。当一个Context取消所有从它导出的Contexts都会被取消。
- WithCancel、WithDeadline、WithTimeout函数携带一个Context(父)并返回一个导出的Context(子)和一个CancelFunc(取消函数)。调用CancelFunc函数来取消子和他的孩子,移除父母的参考孩子,并停止任何关联的定时器。调用CancelFunc失败会泄露子和他的孩子直到父取消或者计时器超时。go的审查工具被用在所有的control-flow路径下检查CancelFuncs。
程序在使用Context应遵循如下规则,以保证接口的一致,并允许静态分析工具检查Context传递。
1. 不要将 Contexts 放入结构体,相反context应该作为第一个参数传入,命名为ctx。
func DoSomething(ctx context.Context, arg Arg) error { ... use ctx ...}
2. 即使函数允许也不要传递一个nil的Context。如果不确定使用哪种Conetex,传递context.TODO
3. 使用context的Value相关方法只应该用于在程序和接口中传递的和请求相关的数据,不要用它来传递一些可选的参数。
4. 相同的Context可以在不同的goroutines中传递,Contexts是线程安全的。
Context包的核心
// context 包里的方法是线程安全的,可以被多个 goroutine 使用 type Context interface { // 如果存在,Deadline 返回Context将要关闭的时间 Deadline() (deadline time.Time, ok bool) // 当Context 被 canceled 或是 times out 的时候,Done 返回一个被 closed 的channel Done() <-chan struct{} // 在 Done 的 channel被closed 后, Err 代表被关闭的原因 Err() error // 如果存在,Value 返回与 key 相关了的值,不存在返回 nil Value(key interface{}) interface{}}
Context包中的导出方法
- Background()
该函数返回空的Context,该Context一般由接收请求的第一个Goroutine创建,是与进入请求对应的Context根节点,它不能被取消、没有值、也没有过期时间。它常常作为处理Request的顶层context存在。 - TODO()
该函数返回空的Context,可以使用context.TODO,当不清楚使用哪个Context,或者不确定哪个可使用。 - CancelFunc()
该函数通知放弃操作者的工作,并不会等待工作停止。第一次调用之后,在调用不会做任何操作。 - WithCancel(parent Context)
该函数返回一个 cancelCtx ,同时返回一个 CancelFunc,CancelFunc 是 context 包中定义的一个函数类型:type CancelFunc func()。调用这个 CancelFunc 时,关闭对应的c.done,也就是让他的后代goroutine退出。 - WithDeadline(parent Context, deadline time.Time)
该函数返回的Context类型值同样是parent的副本,但其过期时间由deadline和parent的过期时间共同决定。当parent的过期时间早于传入的deadline时间时,返回的过期时间应与parent相同。父节点过期时,其所有的子孙节点必须同时关闭;反之,返回的父节点的过期时间则为deadline。 - WithTimeout(parent Context, timeout time.Duration)
WithTimeout函数与WithDeadline类似,只不过它传入的是从现在开始Context剩余的生命时长。他们都同样也都返回了所创建的子Context的控制权,一个CancelFunc类型的函数变量。 - WithValue(parent Context, key, val interface{})
返回parent的一个副本,调用该副本的Value(key)方法将得到val。这样我们不光将根节点原有的值保留了,还在子孙节点中加入了新的值,注意若存在Key相同,则会被覆盖。
示例1 主动停止gorutine
import ( "context" "fmt" "time")func run(ctx context.Context,threadId int){ for { select { case <-ctx.Done(): fmt.Println("timeout") default: fmt.Println("thred runing ", threadId) } }}func timeout(cancel context.CancelFunc){ time.Sleep( 1 * time.Second) //取消 cancel()}func main() { //使用Backgroud() ctx, cancel := context.WithCancel(context.Background()) go run(ctx,1) go run(ctx,2) go run(ctx,3) go timeout(cancel) time.Sleep(2 * time.Second)}
执行以上程序,会看到不断的在打印threadId直到timeout调用了cancel主动停止,后开始不断打印timeout直至主程序退出。示例主要展示了WithCancel,Background的用法。
在上面的例子中我们自己手写了一个timeout,context包中已经给我们提供好了,下面我们就改造下。
示例2 使用WithDeadline,WithTimeout
import ( "context" "fmt" "time")func run(ctx context.Context,threadId int){ for { select { case <-ctx.Done(): fmt.Println("timeout") default: fmt.Println("thred runing ", threadId) } }}func main() { ctx, cancel := context.WithTimeout(context.Background(),1 * time.Second) defer cancel() go run(ctx,1) go run(ctx,2) go run(ctx,3) time.Sleep(2 * time.Second)}
由于WithTimeout与WithDeadline功能类似就不在举例了,运行以上示例与示例1输出同样的结果。
示例3 传递数据
import ( "context" "fmt" "time")var key string = "Hello word!"func run(ctx context.Context){ for { select { case <-ctx.Done(): fmt.Println("timeout") default: fmt.Println(ctx.Value(key)) } }}func main() { ctx, cancel := context.WithTimeout(context.Background(),1 * time.Second) value := context.WithValue(ctx,key,"This is my test") defer cancel() go run(value) time.Sleep(2 * time.Second)}
- Go Context包使用
- Go语言并发模型:使用 context
- golang Context包的使用
- Go学习笔记:time包使用
- kubernetes client-go包使用示例
- 【Go】包
- <5> go 上下文传递context
- 使用两个context实现CLOSE包的超时等待
- 使用 go 写一个检测 tcp udp 状态的包
- go语言闭包,匿名函数,变量使用
- 举例讲解Go语言中函数的闭包使用
- 使用go读取gzip格式的压缩包
- Golang context包入门
- GOLANG context包
- Go语言_HTTP包
- [go语言]包
- Go path包
- Go user包
- Reinforcement Learning_By David Silver笔记一: Introduction
- Algorithm之路八:String to Imteger
- Delaunay三角网生成算法
- [转载]Ubuntu 16.04编译安装OpenCV(Python2 /python3)(使用虚拟环境)
- 快速删除所有空值:汪琪玩Excel第十四招
- Go Context包使用
- C#model类与XML转换类
- 使用python实现正整数的阶乘
- LMA和VMA
- 前端小白--CSS实现水平垂直居中
- FGSM(Fast Gradient Sign Method)生成对抗样本(32)---《深度学习》
- Vegas文字投影的模糊效果怎么制作?
- Unity响应Android的返回键,Home键
- Android bat批处理自动执行adb shell命令