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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 笔记本电脑玩dnf卡怎么办 龙之谷约惠码被删了怎么办 天涯明月刀马没有了怎么办 icloud照片无法同步怎么办 ipad不能下载app怎么办 ipad屏幕孔进水怎么办 ipad无法验证登录怎么办 dnf电脑配置低怎么办 淘宝直播粉丝不够怎么办 电脑页面显示不全怎么办 脸上发痒长痘怎么办 扣扣魔性表情泡泡消失怎么办 脚起小泡泡很痒怎么办 孕妇脚痒起水泡怎么办 孕妇手脚起湿疹怎么办 嘴巴破皮了怎么办 小便刺痛阴唇红肿怎么办 集成墙面挂照片怎么办 苹果电脑网页游戏打不开怎么办 苹果6plus发热怎么办 玩手游手机太卡怎么办 苹果七发烫厉害怎么办 苹果手机延迟高怎么办 王者荣耀总是卡怎么办 王者荣耀卡屏怎么办 王者荣耀网络延迟怎么办 荣耀8手机卡了怎么办 荣耀v10有点卡怎么办 荣耀10有点卡怎么办 8g内存吃鸡会崩怎么办 玩看门狗很卡怎么办 拼多多人数不够怎么办 玩cf想吐怎么办 玩手机头晕恶心怎么办 玩手机头疼恶心怎么办 看手机想吐怎么办 英雄联盟取名后怎么办 王者荣耀改名重复怎么办 刺激战场改名重复怎么办 省钱快报忘记密码怎么办 手机直播网速卡怎么办