一、context上下文简介
context简单的理解就是上下文,它可以进行不同协程之间的通信,所以也就包含了上下文的环境等变量信息。有下面三种用法:
- WithCancel 通过该方法可以达到一个协程在某一时刻控制另一个协程的退出
- WithDeadline 通过该方法可以在一个协程在指定时间点控制另一个协程的退出
- WithTimeout 通过该方法进行超时设置,一旦超时,相应的协程就会退出
二、使用方法
1、WithCancel
WithCancel返回一个带着Done通道的context副本以及一个cancel函数,这个带着Done通道的副本在cancel函数被调用或者父context的Done通道被关闭时,它就会关闭。
package main import ( "context" "fmt" "sync" "time" ) var wg sync.WaitGroup func getInfo(ctx context.Context) { defer wg.Done() for { time.Sleep(time.Second) select { case <-ctx.Done(): // 检查cancel是否到时间执行 fmt.Println("获取信息结束!") return default: fmt.Println("获取信息!") } } } func main() { wg.Add(1) ctx, cancel := context.WithCancel(context.Background()) go getInfo(ctx) time.Sleep(time.Second * 5) cancel() // 5s后执行cancel函数 wg.Wait() } /* 获取信息! 获取信息! 获取信息! 获取信息! 获取信息结束! */
2、WithDeadline
WithDeadline返回一个带着截至日期的context副本,如果到达了截至日期,那么这个副本的Done通道的副本在cancel函数被调用或者父context的Done通道被关闭时,它就会关闭。
package main import ( "context" "fmt" "sync" "time" ) var wg sync.WaitGroup func getInfo(ctx context.Context) { defer wg.Done() for { time.Sleep(time.Second) select { case <-ctx.Done(): // 到时间会自动调用cancel函数,结束协程函数 fmt.Println("获取信息结束!") return default: fmt.Println("获取信息!") } } } func main() { wg.Add(1) d := time.Now().Add(time.Second * 5) ctx, _ := context.WithDeadline(context.Background(), d) // 如果没有返回cancel函数也是可行的,只要在规定的d时间内就自动结束传入ctx的函数 go getInfo(ctx) wg.Wait() } /* 获取信息! 获取信息! 获取信息! 获取信息! 获取信息结束! */
3、WithTimeout
WithTimeout返回一个带着超时时间的context副本,如果到达了时间,那么这个Done通道的副本在cancel函数被调用或者父context的Done通道被关闭时,它就会关闭。
如果显式调用cancel函数,那么如果未在超时时间之前也可以结束相应的协程。
package main import ( "context" "fmt" "sync" "time" ) var wg sync.WaitGroup func getInfo(ctx context.Context) { defer wg.Done() for { time.Sleep(time.Second) select { case <-ctx.Done(): // 到时间会自动调用cancel函数,结束协程函数 fmt.Println("获取信息结束!") return default: fmt.Println("获取信息!") } } } func main() { wg.Add(1) ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) go getInfo(ctx) defer cancel() // 超时之后释放资源 wg.Wait() } /* 获取信息! 获取信息! 获取信息! 获取信息! 获取信息结束! */