一、问题的提出:
在 Go http包的Server中,也就是在go的http服务器中,对每一个请求request都会有一个对应的 goroutine 去处理该请求,而且对应的请求处理函数在处理该请求时有可能又会启动新的的 goroutine 用来访问一些后端服务:比如数据库和RPC服务。
而且用来处理同一个请求request的 各goroutine间 通常都需要访问与该request相关的数据,比如终端用户的身份认证信息、验证相关的token、请求的截止时间,那么如何方便的在这些goroutine间(也就是在与处理该request相关的各goroutine间)传递该request域的数据,以及 如何在该request被取消或超时时,及时的关闭所有用来处理该请求的 goroutine?原则上当一个请求被取消或超时时,所有用来处理该请求的 goroutine 都应该迅速退出,然后系统才能释放这些 goroutine 占用的资源。
二、解决方案:
Go 的Context库就是用来解决以上问题的。Go1.7加入了一个新的标准库context,它定义了Context类型。
1、通过func WithValue(parent Context, key, val interface{}) Context
实现request域数据与Context对象的绑定,并且可以通过在不同的goroutine间传递该Context对象或者其派生Context对象来解决:在这些goroutine间(也就是在与处理该request相关的各goroutine间)传递该request域的数据的问题,且各goroutine队该context对象的值操作是并发安全的!!!
2、可以通过往子goroutine或者处理同一个request请求的各goroutine传递一个Context对象,然后通过该传递来的Context的Done通道中是否有值来判定当前任务是否被Cancel或者执行超时了 。这个Done通道即为Done()方法返回的channel通道,当context因超时或者到了截止时间或者被手动cancel时,会自动往其Done通道中存一个值,反言之只要能从Context的Done通道中取出一个值就表示该Context被cancel或者中止了,也就是表示该goroutine的任务被取消了其应被及时关闭,释放其所占的资源。
三、 Context接口
context.Context是一个接口,该接口定义了四个需要实现的方法。
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
其中:
-
Deadline()方法需要返回当前Context被取消的时间,也就是完成工作的截止时间(deadline);
-
Done()方法需要返回一个只读Channel,这个Channel会在当前工作完成或者上下文被取消之后关闭,多次调用Done()方法也只会返回同一个Channel;
-
Err()方法会返回当前Context结束的原因