返回

Context源码剖析

后端

1. 前言

在 Go 1.17 版本中,context 包被引入到标准库,并迅速成为 Go 开发者必不可少的工具之一。context 包提供了对请求上下文(Context)的管理和使用,允许我们在代码中传递请求相关的信息,并在适当的时候取消或超时请求。

context.Context 是一个接口,它定义了以下方法:

  • Done():返回一个通道,当上下文被取消时关闭。
  • Err():返回一个错误,表示上下文被取消的原因。
  • Value(key interface{}) interface{}:从上下文中获取一个值。
  • WithCancel():创建一个新的上下文,该上下文可以被取消。
  • WithDeadline(deadline time.Time):创建一个新的上下文,该上下文在指定截止时间后会自动取消。
  • WithValue(key interface{}, val interface{}) Context:创建一个新的上下文,该上下文中包含一个新的键值对。

2. context 包的内部实现

context 包的内部实现非常简单,它主要由以下几个部分组成:

  • Context 接口 :定义了 Context 的方法,用于管理和使用请求上下文。
  • cancelCtx 结构体 :实现了 Context 接口,它维护了一个通道,用于通知请求被取消。
  • withCancel 函数 :创建一个新的 Context,该 Context 可以被取消。
  • withDeadline 函数 :创建一个新的 Context,该 Context 在指定截止时间后会自动取消。
  • WithValue 函数 :创建一个新的 Context,该上下文中包含一个新的键值对。

3. 如何使用 context 包

context 包的使用非常简单,我们可以通过以下步骤来使用它:

  1. 首先,我们需要创建一个 context.Context 对象。我们可以使用 context.Background() 函数创建一个空的 Context 对象,也可以使用 context.WithCancel() 函数或 context.WithDeadline() 函数创建一个新的 Context 对象。
  2. 接下来,我们可以使用 context.Context 对象来传递请求相关的信息。我们可以使用 context.Value() 方法从 Context 对象中获取值,也可以使用 context.WithValue() 方法向 Context 对象中添加值。
  3. 当我们需要取消请求时,我们可以使用 context.Cancel() 方法来取消 Context 对象。这会关闭 Context 对象的 Done() 通道,并导致使用该 Context 对象的所有 goroutine 退出。
  4. 当我们需要等待请求完成时,我们可以使用 context.Done() 通道来等待 Context 对象被取消。当 Context 对象被取消时,Done() 通道会关闭,我们可以使用 select 语句来等待 Done() 通道关闭。

4. context 包的最佳实践

在使用 context 包时,我们需要遵循以下最佳实践:

  • 始终在函数签名中显式声明 Context 参数。这可以帮助我们明确地知道函数需要一个 Context 对象,并避免在使用 Context 对象时出现错误。
  • 尽量使用 context.Background() 函数创建一个空的 Context 对象。这可以避免在不必要的情况下创建新的 Context 对象。
  • 在需要取消请求时,使用 context.Cancel() 方法来取消 Context 对象。这可以避免在不必要的情况下继续执行请求。
  • 在需要等待请求完成时,使用 context.Done() 通道来等待 Context 对象被取消。这可以避免在请求完成之前继续执行代码。

5. 总结

context 包是一个非常有用的工具,它可以帮助我们在并发编程中管理和使用请求上下文。通过使用 context 包,我们可以轻松地取消或超时请求,并传递请求相关的信息。