作用
1、web编程中,一个请求对应多个goroutine之间的数据交互
2、超时控制,控制异步请求超时
3、上下文控制,跟踪请求的流程
结构
1、底层结构
// 请求上下文信息
context
// 作用:用来简化对于处理单个请求的多个gouroutine之间与请求域的数据,取消信号,截止时间等相关操作
type Context interface {
// 设置的截止时间
// deadline : 到了该时间点,context会自动发起取消请求
// ok == false 表示 没有设置截止时间,如果需要取消的话,需要调用取消函数
Deadline() (deadline time.Time, ok bool)
// 返回一个只读的chan,类型为struct{},
// 在goroutine中,如果该方法返回的chan可以读取,则意味着parent context已经发起了取消请求,通过Done()方法收到这个信号后,应该做清理操作,
// 然后退出goroutine,释放资源,之后Err()方法会返回一个错误,告知为什么Context被取消
Done() <-chan struct{}
//返回取消的错误原因,因为什么Context被取消
Err() error
//获取Context上绑定的值,是一个健值对,通过key才可以获取对应的值
Value(key interface{}) interface{}
}
Context的继承
// 传递一个父Context为参数,返回子Context及一个取消函数来取消Context
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
// 与WithCannel类似,会多传递一个截止时间参数,意味着到了这个时间点,会自动取消Context,当前我们也可以不等到这个时候,提前调用取消函数进行取消
func WithDeadline(parent Context, deadline time.Time)(Context,CancelFunc)
// 与WithDeadline基本一样,提供一个时间长度,多长时间后自动取消
func WithTimeout(parent Context,timeout time.Duration)(Context,CancelFunc)
// 是为了生成一个绑定了一个健值对数据的Context,绑定的数据可以通过Context.Value方法访问
func WithValue(parent Context, key ,val interface{}) Context
2、空的结构
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
return
}
func (*emptyCtx) Done() <-chan struct{} {
return nil
}
func (*emptyCtx) Err() error {
return nil
}
func (*emptyCtx) Value(key interface{}) interface{} {
return nil
}
func (e *emptyCtx) String() string {
switch e {
case background:
return "context.Background"
case todo:
return "context.TODO"
}
return "unknown empty Context"
}
3、传值结构
// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type valueCtx struct {
Context
key, val interface{}
}
4、取消结构
// A cancelCtx can be canceled. When canceled, it also cancels any children
// that implement canceler.
type cancelCtx struct {
Context
mu sync.Mutex // protects following fields
done chan struct{} // created lazily, closed by first cancel call
children map[canceler]struct{} // set to nil by the first cancel call
err error // set to non-nil by the first cancel call
}
5、超时结构
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
// implement Done and Err. It implements cancel by stopping its timer then
// delegating to cancelCtx.cancel.
type timerCtx struct {
cancelCtx
timer *time.Timer // Under cancelCtx.mu.
deadline time.Time
}
案例
1、传值
// with_value
// 传值
func with_value() {
// 声明一个根上下文信息
ctx, cancel := context.WithCancel(context.Background())
valueCtx := context.WithValue(ctx, "key", "add value")
go watch(valueCtx)
time.Sleep(5 * time.Second)
cancel()
time.Sleep(1 * time.Second)
}
func watch(ctx context.Context) {
fmt.Println("go watch")
for {
select {
case <-ctx.Done():
// 上下文被取消
fmt.Println(ctx.Value("key"), "is cancel")
time.Sleep(1 * time.Second)
default:
fmt.Println(ctx.Value("key"), "int goroutine")
time.Sleep(1 * time.Second)
}
}
}
2、设置截止时间
// with_deadtime
// 截止时间
func with_deadtime() {
dt := time.Now().Add(3 * time.Second)
ctx, cancel := context.WithDeadline(context.Background(), dt)
defer cancel()
go func(ctx context.Context) {
for {
select {
case <-time.After(2 * time.Second):
fmt.Println("到达截止时间")
case <-ctx.Done():
fmt.Println("上下文取消")
return
}
}
}(ctx)
time.Sleep(5 * time.Second)
}
3、设置超时
// with_timeout
// 超时
func with_timeout() {
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
defer cancel()
fmt.Println("with_timeout start")
var wg sync.WaitGroup
wg.Add(1)
go work(ctx, &wg)
wg.Wait()
fmt.Println("with_timeout end")
}
func work(ctx context.Context, wg *sync.WaitGroup) error {
defer wg.Done()
for i := 0; i < 1000; i++ {
select {
case <-time.After(1 * time.Second):
fmt.Println("指定时间", i)
case <-ctx.Done():
fmt.Println("Cancel context", i)
return ctx.Err()
}
}
return nil
}
4、并发请求一个超时取消所有的请求
func task1() int {
time.Sleep(3 * time.Second)
return 1
}
func task2() int {
time.Sleep(2 * time.Second)
return 2
}
func task3() int {
time.Sleep(2 * time.Second)
return 3
}
// with_url
// 一个请求触发三个任务 并发完成,出现一个超时则全部取消
// 1、要求处理三个结果之和
// 2、返回时间不超过指定时间
func with_url() {
var res, sum int
// 请求标志
sucess := make(chan int)
// 保存每个任务的结果
resChan := make(chan int, 3)
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
defer cancel()
// 使用sync保证任务全部完成之后推出
var wg sync.WaitGroup
wg.Add(3)
go func() {
resChan <- task1()
wg.Done()
}()
go func() {
resChan <- task2()
wg.Done()
}()
go func() {
resChan <- task3()
wg.Done()
}()
go func() {
for {
select {
case res = <-resChan:
sum += res
fmt.Println("add", res)
case <-sucess:
fmt.Println("所有任务完成之后的结果", sum)
// wg.Done()
return
case <-ctx.Done():
fmt.Println("出现超时后的结果", sum)
// wg.Done()
return
}
}
}()
wg.Wait()
// 表示任务已经完成
sucess <- 1
}
func main() {
with_url()
}