go语言中goroutine之间的关联关系,缺少维护,在erlang中有专门的机制来保障新开协程的生命周期,在go语言中,只能经过channel + select来实现,但不够直观,很绕。
Context 一般被译做 上下文 ,它是一个比较抽象的概念,通常理解为程序单元的一个运行状态、现场、快照。上下上下则是存在上下层的传递, 上 会把内容传递给 下 。
在Go语言中,程序单元也就指的是Goroutine。context 包不只实现了在程序单元之间共享状态变量的方法,同时能经过简单的方法,使咱们在被调用程序单元的外部,经过设置ctx变量值,将过时或撤销信号传递给被调用的程序单元。html
在go服务器中(http服务器),对于每一个请求的request都是在单独的goroutine中进行的,处理一个request也可能涉及多个goroutine之间的交互, 使用context可使开发者方便地在这些goroutine里传递request相关的数据、取消goroutine的signal或截止时间golang
Done 方法在Context被取消或超时时返回一个close的channel,close的channel能够做为广播通知,告诉给context相关的函数要中止当前工做而后返回。安全
当一个父operation启动一个goroutine用于子operation,这些子operation不可以取消父operation。下面描述的WithCancel函数提供一种方式能够取消新建立的Context.服务器
Context能够安全的被多个goroutine使用。开发者能够把一个Context传递给任意多个goroutine而后cancel这个context的时候就可以通知到全部的goroutine。ide
Err方法返回context为何被取消。函数
Deadline返回context什么时候会超时。协程
Value返回context相关的数据。htm
须要注意的就是 调用CancelFunc会取消child以及child生成的context,取出父context对这个child的引用,中止相关的计数器blog
实战:生命周期
参考示例1:
package main import ( "context" "log" "os" "time" ) var logg *log.Logger func someHandler() { ctx, cancel := context.WithCancel(context.Background()) go doStuff(ctx) //10秒后取消doStuff time.Sleep(10 * time.Second) cancel() } //每1秒work一下,同时会判断ctx是否被取消了,若是是就退出 func doStuff(ctx context.Context) { for { time.Sleep(1 * time.Second) select { case <-ctx.Done(): logg.Printf("done") return default: logg.Printf("work") } } } func main() { logg = log.New(os.Stdout, "", log.Ltime) someHandler() logg.Printf("down") time.Sleep(10 * time.Second) }
输出
18:00:17 work 18:00:18 work 18:00:19 work 18:00:20 work 18:00:21 work 18:00:22 work 18:00:23 work 18:00:24 work 18:00:25 work 18:00:26 down 18:00:26 done
参考示例2:
package main import ( "context" "log" "os" "time" ) var logg *log.Logger func doTimeOutStuff(ctx context.Context) { for { time.Sleep(1 * time.Second) if deadline, ok := ctx.Deadline(); ok { //设置了deadl logg.Printf("deadline set") if time.Now().After(deadline) { logg.Printf(ctx.Err().Error()) return } } select { case <-ctx.Done(): logg.Printf("done") return default: logg.Printf("work") } } } func timeoutHandler() { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) // ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(5*time.Second)) go doTimeOutStuff(ctx) // go doStuff(ctx) time.Sleep(10 * time.Second) cancel() } func main() { logg = log.New(os.Stdout, "", log.Ltime) timeoutHandler() logg.Printf("down") time.Sleep(10 * time.Second) }
输出:
18:04:37 deadline set 18:04:37 work 18:04:38 deadline set 18:04:38 work 18:04:39 deadline set 18:04:39 work 18:04:40 deadline set 18:04:40 work 18:04:41 deadline set 18:04:41 context deadline exceeded 18:04:46 down
参考连接:
https://studygolang.com/articles/12566
https://www.cnblogs.com/zhangboyu/p/7456606.html
https://studygolang.com/articles/13866?fr=sidebar