Golang中的 Context 包

技术 · 2023-06-21
Golang中的 Context 包

这是Go标准库中的包之一,优雅、功能强大、编写良好且文档齐全。大多数Go开发者的初级阶段都觉得它更令人困惑,就像我在学习Go程序的早期阶段所遇到的那样,迷茫不知道如何上手。

原理

如下图所示:
1_tZuAzOdbRz17AlO-SSzVpg.jpg
Golang 中context的入口点是上下文包,它是一个根节点emptyCtx,我们需要的任何上下文(Context)都将是根(emptyCtx)上下文的子级。

当需要带有cancel - cancelCtx的上下文时,它实际上会采用父级上下文(空Context),在本例中context.Background()返回的就是一个emptyCtx,并且它将生成以context.Background()作为父级上下文的新上下文,所以我们可以从先前的上下文创建任何上下文作为父上下文,这样就形成了一个图表,也类似于我们常说的树这种数据结构。

如果父级上下文被取消(cancel),取消实际上会传播到其所有子级及其子级的所有子级,因此我们在复杂的并发编程中非常有用。

应用

context中有以下几个场景方法:
1__Pn8Qo_X5T8zjwE_iFe8gg.webp
上面的Background()TODO()都是空上下文,但是一般我们都使用context.Background()作为根上下文,其余的都是派生上下文

  • 比方说,当你处理某种取消信号时,我们使用带有取消(cancel)的上下文,该函数实际上采用父级上下文,然后返回一个新的上下文和取消函数(cancel()),以便我们可以将取消函数用于取消信号

    ctx := context.Background() // 根节点
    ctx, cancel := context.WithCancel(ctx) // 带有取消函数的子级节点
  • 如果我们想设置 Xhr 请求和 go 执行中超时时间,那么我们使用超时(WithTimeout)过期时间(WithDeadline)上下文

    // WithTimeout
    ctx := context.Background()
    ctx, cancle := context.WithTimeout(ctx, 2*time.Second) // 2s 超时
    
    // WithDeadline
    ctx := context.Background()
    deadline := time.Now().Add(2*time.Second) // 2s后过期
    ctx, cancel := context.WithDeadline(ctx, deadline)
  • 如果在 api 前发送一些请求范围的值,我们可能会使用 WithValue

    ctx := context.Background()
    ctx, cancel := context.WithTimeout(ctx, 2*time.Second)
    ctx := context.WithValue(ctx, "data", 1) // 设置data为1
    fmt.Println(ctx.Value("data").(int)) // 获取data的值

    下面我们来看一下context内部的实现:
    2023-06-21T12:45:44.png
    上图可以看出,context包,Context有四个方法,这四个函数的作用如下:

  • Deadline:返回 context 是否会被取消以及自动取消时间(即 deadline)
  • Done: 当 context 被取消或者到了 deadline,返回一个被关闭的 channel
  • Err: 在 channel Done 关闭后,返回 context 取消原因
  • Value: 返回与特定键关联的值,当想在上下文获取存在一个指定key的值的时候可以通过ctx.Value("key")方法去获取

上面这个四个方法都是幂等的。也就是说连续多次调用同一个方法,得到的结果都是相同的。

至此context的简单介绍就道理。后面在去说明context里面的具体实现。

并发编程 Context
Theme Jasmine by Kent Liao