译|Go Concurrency Patterns: Context(上)

简介: 译|Go Concurrency Patterns: Context

在 Go 服务中,每个传入的请求在单独的 goroutine 中处理。请求回调函数通常启动额外的 goroutine 以访问后端,如数据库和RPC服务。处理同一请求的一系列 goroutine 通常需要访问请求相关的值,例如端用户的标识、授权令牌和请求截止时间。当请求被取消或超时,处理该请求的所有 goroutine 都应该快速退出,以便系统可以回收它们正在使用的资源。

在 Google,我们开发了一个上下文包,可以轻松地跨越 API边界,将请求作用域内的值、取消信号和截止时间传递给所有处理请求的 goroutine。该包的公共可用版本为 context。本文描述了如何使用这个包,并提供了一个完整的示例。

Context

context 包的核心是 Context 类型:

// A Context carries a deadline, cancelation signal, and request-scoped values
// across API boundaries. Its methods are safe for simultaneous use by multiple
// goroutines.
type Context interface {
    // Done returns a channel that is closed when this Context is canceled
    // or times out.
    Done() <-chan struct{}
    // Err indicates why this context was canceled, after the Done channel
    // is closed.
    Err() error
    // Deadline returns the time when this Context will be canceled, if any.
    Deadline() (deadline time.Time, ok bool)
    // Value returns the value associated with key or nil if none.
    Value(key interface{}) interface{}
}

(此描述是精简的;godoc 是权威的。)

Done 方法返回一个 channel,充当传递给 Context 下运行的函数的取消信号:当 channel 关闭时,函数应该放弃它们的工作并返回。Err 方法返回一个错误,表明取消 context 的原因。文章 Pipelines and Cancelation 更详细地讨论了 Done channel 的习惯用法。

Context 没有 Cancel 方法,原因与 Done channel 是只读的一样:接收取消信号的函数通常不是发送信号的函数。特别是当父操作为子操作启动 goroutine 时,子操作不应该有能力取消父操作。相反,WithCancel 函数(如下所述)提供了一种取消新 Context 值的方法。

多个 goroutine 同时使用同一 Context 是安全的。代码可以将单个 Context 传递给任意数量的 goroutine,并取消该 Context 以向所有 goroutine 发送信号。

Deadline 方法允许函数决定是否应该开始工作;如果剩下的时间太少,则可能不值得。代码还可以使用截止时间来设置I/O操作超时。

Value 允许 Context 携带请求作用域的数据。为使多个 goroutine 同时使用,这些数据必须是安全的。

Derived contexts

context 包提供了从现有 Context 值派生新 Context 值的函数。这些值形成一个树:当 Context 被取消时,从它派生的所有 Context 也被取消。

Background 是所有 Context 树的根;它永远不会被取消:

// Background returns an empty Context. It is never canceled, has no deadline,
// and has no values. Background is typically used in main, init, and tests,
// and as the top-level Context for incoming requests.
func Background() Context

WithCancelWithTimeout 返回派生 Context 值,可以比父 Context 更早取消。当请求回调函数返回时,通常会取消与传入请求关联的 ContextWithCancel 还可用于使用多个副本时取消冗余的请求。WithTimeout 用于设置对后端服务器请求的截止时间:

// WithCancel returns a copy of parent whose Done channel is closed as soon as
// parent.Done is closed or cancel is called.
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
// A CancelFunc cancels a Context.
type CancelFunc func()
// WithTimeout returns a copy of parent whose Done channel is closed as soon as
// parent.Done is closed, cancel is called, or timeout elapses. The new
// Context's Deadline is the sooner of now+timeout and the parent's deadline, if
// any. If the timer is still running, the cancel function releases its
// resources.
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)

WithValue 提供了一种将请求作用域的值与 Context 关联的方法:

// WithValue returns a copy of parent whose Value method returns val for key.
func WithValue(parent Context, key interface{}, val interface{}) Context

通过一个示例了解使用 context 包的最佳方法。

示例:Google Web搜索

我们的示例是一个 HTTP 服务器,它处理 URL,如 _/search?q=golang&timeout=1s_,将查询 “golang” 转发到 google web search api 并渲染结果。timeout 参数告诉服务器在该延时后取消请求。

代码分为三个包:

  • server 提供了 /search 的 main 函数和请求回调函数。
  • userip 提供了从请求中提取用户 IP 地址并将其与 Context 关联的函数。
  • google 提供了向 Google 发送查询的 search 函数。
目录
相关文章
|
5月前
|
Go
go语言并发编程(五) ——Context
go语言并发编程(五) ——Context
|
1月前
|
存储 Go 数据库
Go语言Context包源码学习
【10月更文挑战第21天】Go 语言中的 `context` 包用于在函数调用链中传递请求上下文信息,支持请求的取消、超时和截止时间管理。其核心接口 `Context` 定义了 `Deadline`、`Done`、`Err` 和 `Value` 方法,分别用于处理截止时间、取消信号、错误信息和键值对数据。包内提供了 `emptyCtx`、`cancelCtx`、`timerCtx` 和 `valueCtx` 四种实现类型,满足不同场景需求。示例代码展示了如何使用带有超时功能的上下文进行任务管理和取消。
|
3月前
|
存储 SQL Go
一文弄懂Go语言的Context包,值得收藏!
在开发高效的Go应用程序时,处理超时、取消操作和传递请求范围的数据至关重要。Go标准库中的`context`包提供了一套强大的工具,用于在不同层级间传递取消信号、超时和截止时间等信息。本文首先概述了`context`包的核心功能,接着详细介绍了关键方法,如`WithCancel`、`WithDeadline`、`WithTimeout`和`WithValue`的使用场景。通过创建和派生上下文,开发者能更好地管理请求的生命周期,控制长时间运行的操作,并在并发环境中传递必要的数据。
53 1
|
6月前
|
数据管理 Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第25天】Go语言中的`context`包在并发、网络请求和长任务中至关重要,提供取消、截止时间和元数据管理。本文探讨`context`基础,如`Background()`、`TODO()`、`WithCancel()`、`WithDeadline()`和`WithTimeout()`。常见问题包括不当传递、过度使用`Background()`和`TODO()`以及忽略错误处理。通过取消和超时示例,强调正确传递上下文、处理取消错误和设置超时以提高应用健壮性和响应性。正确使用`context`是构建稳定高效Go应用的关键。
104 1
|
6月前
|
Go 开发者
Golang深入浅出之-Go语言上下文(context)包:处理取消与超时
【4月更文挑战第23天】Go语言的`context`包提供`Context`接口用于处理任务取消、超时和截止日期。通过传递`Context`对象,开发者能轻松实现复杂控制流。本文解析`context`包特性,讨论常见问题和解决方案,并给出代码示例。关键点包括:1) 确保将`Context`传递给所有相关任务;2) 根据需求选择适当的`Context`创建函数;3) 定期检查`Done()`通道以响应取消请求。正确使用`context`包能提升Go程序的控制流管理效率。
66 1
|
6月前
|
存储 安全 程序员
一文搞懂Go语言Context
一文搞懂Go语言Context
63 0
|
6月前
|
SQL Go 数据库
Go语言Context应用全攻略:异步编程利器
Go语言Context应用全攻略:异步编程利器
170 0
|
6月前
|
安全 Go 数据库
Go语言高级特性:Context深入解读
Go语言高级特性:Context深入解读
47 0
Go 语言 context 最佳实践教程
Go 语言 context 最佳实践教程
372 1
|
安全 Go
Go 语言 context 最佳实践
Go 语言 context 最佳实践
71 0