go
来源:互联网 发布:lte重叠覆盖优化 编辑:程序博客网 时间:2024/04/27 22:02
1,context作用
1,通过context,我们可以方便地对同一个请求所产生地goroutine进行约束管理,可以设定超时、deadline,甚至是取消这个请求相关的所有goroutine。形象地说,假如一个请求过来,需要A去做事情,而A让B去做一些事情,B让C去做一些事情,A、B、C是三个有关联的goroutine,那么问题来了:假如在A、B、C还在处理事情的时候请求被取消了,那么该如何优雅地同时关闭goroutine A、B、C呢?这个时候就轮到context包上场了。
2,在golang中的创建一个新的线程并不会返回像c语言类似的pid所有我们不能从外部杀死某个线程,所有我就得让它自己结束之前我们用channel+select的方式,来解决这个问题但是有些场景实现起来比较麻烦,例如由一个请求衍生出多个线程并且之间需要满足一定的约束关系,以实现一些诸如:
有效期,中止线程树,传递请求全局变量之类的功能。
于是google 就为我们提供一个解决方案,开源了context包。使用context包来实现上下文功能 …..
约定:需要在你的方法的传入参数的第一个参数是context.Context的变量。
2,context结构
使用例子(1):
package mainimport ( "context" "fmt")func main() { // gen generates integers in a separate goroutine and // sends them to the returned channel. // The callers of gen need to cancel the context once // they are done consuming generated integers not to leak // the internal goroutine started by gen. // 定义 goroutine 函数 gen := func(ctx context.Context) <-chan int { dst := make(chan int) n := 1 go func() { for { select { case <-ctx.Done(): return // returning not to leak the goroutine case dst <- n: n++ } } }() return dst } ctx, cancel := context.WithCancel(context.Background()) defer cancel() // main 方法执行完后,结束 ctx 相关的 goroutine for n := range gen(ctx) { fmt.Println(n) if n == 5 { break } }}
使用例子(2):
package mainimport ( "fmt" "time" "golang.org/x/net/context")func Cdd(ctx context.Context) int { fmt.Println(ctx.Value("NLJB")) select { // 结束时候做点什么 ... case <-ctx.Done(): return -3 default: // 没有结束 ... 执行 ... }}func Bdd(ctx context.Context) int { fmt.Println(ctx.Value("HELLO")) fmt.Println(ctx.Value("WROLD")) ctx = context.WithValue(ctx, "NLJB", "NULIJIABEI") go fmt.Println(Cdd(ctx)) select { // 结束时候做点什么 ... case <-ctx.Done(): return -2 default: // 没有结束 ... 执行 ... }}func Add(ctx context.Context) int { ctx = context.WithValue(ctx, "HELLO", "WROLD") ctx = context.WithValue(ctx, "WROLD", "HELLO") go fmt.Println(Bdd(ctx)) select { // 结束时候做点什么 ... case <-ctx.Done(): return -1 default: // 没有结束 ... 执行 ... }}func main() { // 自动取消(定时取消) { timeout := 3 * time.Second ctx, _ := context.WithTimeout(context.Background(), timeout) fmt.Println(Add(ctx)) } // 手动取消 // { // ctx, cancel := context.WithCancel(context.Background()) // go func() { // time.Sleep(2 * time.Second) // cancel() // 在调用处主动取消 // }() // fmt.Println(Add(ctx)) // } select {}}
(1)context.Context 接口
- context包里的方法是线程安全的,可以被多个线程使用
- 当Context被canceled或是timeout, Done返回一个被closed 的channel
- 在Done的channel被closed后, Err代表被关闭的原因
- 如果存在, Deadline 返回Context将要关闭的时间
- 如果存在,Value 返回与 key 相关了的值,不存在返回 nil
// context 包的核心type Context interface { Done() <-chan struct{} Err() error Deadline() (deadline time.Time, ok bool) Value(key interface{}) interface{}}
Deadline会返回一个超时时间,Goroutine获得了超时时间后,例如可以对某些io操作设定超时时间。
Done方法返回一个信道(channel)。当Context被cancenl或timeout时,该信道被关闭。它是一个表示Context是否已关闭的信号。
当Done信道关闭后,Err方法表明Context被撤的原因。
Value可以让Goroutine共享一些数据,当然获得数据是协程安全的。但使用这些数据的时候要注意同步,比如返回了一个map,而这个map的读写则要加锁。
(2)接口的实现
我们不需要手动实现这个接口,context 包已经给我们提供了两个
- Background
- TODO
这两个函数都会返回一个Context的实例只是返回的这两个实例都是空 Context。
/* TODO返回一个非nil,empty的上下文 在目前还不清楚要使用的上下文或尚不可用时*/context.TODO()/* Background返回一个非nil,empty的上下文。 这是没有取消,没有值,并且没有期限。 它通常用于由主功能,初始化和测试,并作为输入的顶层上下文*/context.Background()
3,context包里的方法
(1)方法的使用
Context接口没有提供方法来设置其值和过期时间,也没有提供方法直接将其自身撤销。也就是说,Context不能改变和撤销其自身。那么该怎么通过Context传递改变后的状态呢?
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 interface{}, val interface{}) Context
WithCancel 对应的是 cancelCtx ,其中,返回一个 cancelCtx ,同时返回一个 CancelFunc,CancelFunc 是 context 包中定义的一个函数类型:type CancelFunc func()。调用这个 CancelFunc 时,关闭对应的c.done,也就是让他的后代goroutine退出
WithDeadline 和 WithTimeout 对应的是 timerCtx ,WithDeadline 和 WithTimeout 是相似的,WithDeadline 是设置具体的 deadline 时间,到达 deadline 的时候,后代 goroutine 退出,而 WithTimeout 简单粗暴,直接 return WithDeadline(parent, time.Now().Add(timeout))
WithValue 对应 valueCtx ,WithValue 是在 Context 中设置一个 map,拿到这个 Context 以及它的后代的 goroutine 都可以拿到 map 里的值
Context 的调用应该是链式的,通过WithCancel,WithDeadline,WithTimeout或WithValue派生出新的 Context。当父 Context 被取消时,其派生的所有 Context 都将取消。
通过context.WithXXX都将返回新的 Context 和 CancelFunc。调用 CancelFunc 将取消子代,移除父代对子代的引用,并且停止所有定时器。未能调用 CancelFunc 将泄漏子代,直到父代被取消或定时器触发。go vet工具检查所有流程控制路径上使用 CancelFuncs。
(2)context的创建
所有的context的父对象,也叫根对象,是一个空的context,它不能被取消,它没有值,从不会被取消,也没有超时时间,它常常作为处理request的顶层context存在,然后通过WithCancel、WithTimeout函数来创建子对象来获得cancel、timeout的能力
当顶层的request请求函数结束后,我们就可以cancel掉某个context,从而通知别的routine结束
其它方法例子
请参考:快速掌握 Golang context 包,简单示例
参考
快速掌握 Golang context 包,简单示例
理解Go Context机制
Golang之Context的使用
golang context初探
未读文章
How to correctly use context.Context in Go 1.7
Context API explained
Go Concurrency Patterns: Context
- Go!
- GO
- GO !
- go
- Go
- Go.
- go
- GO!
- go
- Go
- go
- 【GO】
- go
- go
- GO
- Go
- go
- GO
- javaScript算法--字符串反转
- jquery和js
- Pro MySQL NDB Cluster.pdf 英文原版 免费下载
- 机器学习之聚类(一)密度聚类DBSCAN
- 爱因斯坦:量子物理与抽象数学(广义)
- go
- leetcode Some questions of Edit Distance
- APUE之进程笔记(下)
- 手把手教你用1行代码实现人脸识别 -- Python Face_recognition
- tfrecords的分类处理 one hot
- 使用eclipse在tomcat下部署项目不覆盖配置文件server.xml
- Android开发之蓝牙通信(三)
- 【java多线程编程核心技术】1.java多线程技能-笔记总结
- Android软键盘弹出