作为一名 Gopher,怎么可以不知道 Go context 呢?快来了解一下吧!
介绍
Go 1.7 标准库引入 context,中文译作“上下文”,准确说它是 goroutine 的上下文,包含 goroutine 的运行状态、环境、现场等信息。
context 主要用来在 goroutine 之间传递上下文信息,包括:取消信号、超时时间、截止时间、k-v 等。
随着 context 包的引入,标准库中很多接口因此加上了 context 参数,例如 database/sql 包。context 几乎成为了并发控制和超时控制的标准做法。
使用场景
在 Go http 包的 Server 中,每一个请求在都有一个对应的 goroutine 去处理。请求处理函数通常会启动额外的 goroutine 用来访问后端服务,比如数据库和 RPC 服务。用来处理一个请求的 goroutine 通常需要访问一些与请求特定的数据,比如终端用户的身份认证信息、验证相关的 token、请求的截止时间。当一个请求被取消或超时时,所有用来处理该请求的 goroutine 都应该迅速退出,然后系统才能释放这些 goroutine 占用的资源。
使用规范
- 不要将
Context放入结构体,相反Context应该作为第一个参数传入,命名为ctx,例如:
1 | go复制代码func DoSomething (ctx context.Context,arg Arg) error { |
- 即使函数允许,也不要传入
nil的Context。如果不知道用哪种Context,可以使用context.TODO()。 - 使用
Context的Value相关方法只应该用于在程序和接口中传递的和请求相关的元数据,不要用它来传递一些可选的参数。 - 相同的
Context可以传递给在不同的goroutine,因为Context是并发安全的。
Context 结构体
1 | go复制代码// A Context carries a deadline, cancelation signal, and request-scoped values |
Done()返回一个channel。当times out或者调用cancel方法时,将会close掉。Err()返回一个错误。该context为什么被取消掉。Deadline()返回截止时间和 ok。Value()返回Key值。
context 包方法
1 | go复制代码func Background() Context |
Background和TODO都是返回空的Context。WithCancel以一个新的Done channel返回一个父Context的拷贝。WithDeadline的最后期限调整为不晚于deadline返回父上下文的副本。WithTimeout返回WithDeadline(parent, time.Now().Add(timeout))。WithValue返回的父与键关联的值在val的副本。
总结
整个 context 包的源码非常短,很适合学习,一定要去读一下。除了使用 context 控制并发,我们还可以使用 WaitGroup。
本文转载自: 掘金