前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Golang笔记 5.3 上下文 context

Golang笔记 5.3 上下文 context

作者头像
twowinter
发布2020-04-17 11:36:20
6300
发布2020-04-17 11:36:20
举报
文章被收录于专栏:twowintertwowinter

前言

golang 的 Context 包,是专门用来简化多个goroutine之间的上下文同步。

本篇笔记主要参考了 go blog

我正在学习酷酷的 Golang,可点此查看帖子Golang学习笔记汇总

1 库的介绍

Go 语言中的每一个请求的都是通过一个单独的 Goroutine 进行处理的,HTTP/RPC 请求的处理器往往都会启动新的 Goroutine 访问数据库和 RPC 服务,我们可能会创建多个 Goroutine 来处理一次请求,而 Context 的主要作用就是在不同的 Goroutine 之间同步请求特定的数据、同时优雅地结束上下文。

一个实际例子是,在Go服务器程序中,每个请求都会有一个goroutine去处理。然而,处理程序往往还需要创建额外的goroutine去访问后端资源,比如数据库、RPC服务等。由于这些goroutine都是在处理同一个请求,所以它们往往需要访问一些共享的资源,比如用户身份信息、认证token、请求截止时间等。而且如果请求超时或者被取消后,所有的goroutine都应该马上退出并且释放相关的资源。这种情况也需要用Context来为我们取消掉所有goroutine。

一句话:Context 包可以在不同的 Goroutine 之间同步请求数据,还能优雅地设置超时及信号来结束上下文。

2 用法

2.1 Context 定义

context 包的核心是 struct Context,声明如下:

代码语言:javascript
复制
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}

2.2 根 Context

开始上下文的时候是以 Background() 作为最顶层的 parent context,然后再衍生出子context。context.Background() 只是一个空的上下文,没有什么特殊功能,它是上下文中最顶层的默认值.

这些 Context 对象形成一棵树:当一个 Context 对象被取消时,继承自它的所有 Context 都会被取消。两个实现如下:

代码语言:javascript
复制
var (
	background = new(emptyCtx)
	todo = new(emptyCtx)
)

func Background() Context {
	return background
}

func TODO() Context {
	return todo
}

在多数情况下如果函数没有上下文作为入参,我们往往都会使用 context.Background() 作为起始的 Context 向下传递。

例如:

代码语言:javascript
复制
  ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  defer cancel()
  r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})

2.3 衍生的 Context (Derived contexts)

有了如上的父Context,那么是如何衍生更多的子 Context 的呢?这就要靠 context 包为我们提供的 With 系列的函数了。

代码语言:javascript
复制
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, val interface{}) Context

通过这些函数,就创建了一颗Context树,树的每个节点都可以有任意多个子节点,节点层级可以有任意多个。

  • WithCancel函数,传递一个父Context作为参数,返回子Context,以及一个取消函数用来取消Context。
  • WithDeadline函数,和WithCancel差不多,它会多传递一个截止时间参数,意味着到了这个时间点,会自动取消Context,当然我们也可以不等到这个时候,可以提前通过取消函数进行取消。
  • WithTimeout和WithDeadline基本上一样,这个表示是超时自动取消,是多少时间后自动取消Context的意思。
  • WithValue函数和取消Context无关,它是为了生成一个绑定了一个键值对数据的Context,这个绑定的数据可以通过Context.Value方法访问到,这是我们实际用经常要用到的技巧,一般我们想要通过上下文来传递数据时,可以通过这个方法,如我们需要tarce追踪系统调用栈的时候。

例如上面的例子:

代码语言:javascript
复制
  ctx, cancel := context.WithTimeout(context.Background(), time.Second)
  defer cancel()
  r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})

context 会在例子所在的函数结束时调用 延迟函数 cancel() 来结束上下文,同时也可以通过超时来结束上下文。前者是请求成功回复后结束上下文,后者是请求超时未回复后结束上下文。

2.4 注意事项

Do not store Contexts inside a struct type; instead, pass a Context explicitly to each function that needs it. The Context should be the first parameter, typically named ctx:

代码语言:javascript
复制
func DoSomething(ctx context.Context, arg Arg) error {
	// ... use ctx ...
}

3 小结

GO 内置的 Context 包可以在不同的 Goroutine 之间同步请求数据,还能优雅地通过 WithTimeout 设置超时及 WithCancel 设置取消信号来结束上下文。

END

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 1 库的介绍
  • 2 用法
    • 2.1 Context 定义
      • 2.2 根 Context
        • 2.3 衍生的 Context (Derived contexts)
          • 2.4 注意事项
          • 3 小结
          • END
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档