go的context包基本使用

Golang 使用树形派生的方式构造 Context,通过在不同过程 [1] 中传递 deadline 和 cancel 信号,来管理处理某个任务所涉及到的一组 goroutine 的生命周期,防止 goroutine 泄露。并且可以通过附加在 Context 上的 Value 来传递/共享一些跨越整个请求间的数据。

Context 最常用来追踪 RPC/HTTP 等耗时的、跨进程的 IO 请求的生命周期,从而让外层调用者可以主动地或者自动地取消该请求,进而告诉子过程回收用到的所有 goroutine 和相关资源。

context是线程安全的。

 

基本使用代码示例:

 1 package main
 2 
 3 import (
 4     "context"
 5     "fmt"
 6     "time"
 7 )
 8 
 9 // 测试使用context, WithTimeout,WithCancel,WithDeadline,需要在协程内部来检测取消信号,然后退出
10 
11 func main() {
12     // 给一个协程设置超时时间, 5秒后协程自动调用cancel方法
13     ctx, cancelFunc := context.WithTimeout(context.Background(), 5 * time.Second)
14 
15     // 给一个协程设置取消信号,需要取消时,直接执行取消方法
16     ctx2, cancel := context.WithCancel(context.Background())
17     // 给一个协程设置过期时间, 3秒后自动调用cancel方法
18     ctx3, cancelFunc2 := context.WithDeadline(context.Background(), time.Now().Add(3*time.Second))
19     // 设置value
20     ctx4 := context.WithValue(context.Background(), "traceId", "abcdefdg")
21 
22     go testTimeOut(ctx, "监控1")
23     go testTimeOut(ctx, "监控2")
24     go testCancel(ctx2)
25     go testDeadLine(ctx3, "dead 监控1")
26     go testDeadLine(ctx3, "dead 监控2")
27 
28     go testValue(ctx4)
29 
30     time.Sleep(time.Second * 2)
31     // 调用取消
32     cancel()
33 
34     time.Sleep(10000 * time.Second)
35     cancelFunc()  // 最终调用超时
36     cancelFunc2() // 最终调用过期时间
37 }
38 
39 func testTimeOut(ctx context.Context, name string) {
40     for {
41         select {
42         case <-ctx.Done():
43             fmt.Println(name, "执行超时了")
44             return
45         default:
46             fmt.Println(name, "goroutine监控中,time=", time.Now().Unix())
47             time.Sleep(1 * time.Second)
48         }
49     }
50 
51 }
52 
53 func testCancel(ctx context.Context) {
54     // 检测取消信号
55     for {
56         select {
57           case <-ctx.Done():
58               fmt.Println("取消了")
59               return
60         default:
61             fmt.Println("goroutine执行中,time=", time.Now().Unix())
62             time.Sleep(1 * time.Second)
63         }
64     }
65 }
66 
67 
68 func testDeadLine(ctx context.Context, name string) {
69     for {
70         select {
71         case <-ctx.Done():
72             fmt.Println(name, "收到信号,监控退出,time=", time.Now().Unix())
73             return
74         default:
75             fmt.Println(name, "goroutine监控中,time=", time.Now().Unix())
76             time.Sleep(1 * time.Second)
77         }
78     }
79 }
80 
81 // 测试调用value
82 func testValue(ctx context.Context) {
83     traceId, ok := ctx.Value("traceId").(string)
84     if ok {
85         fmt.Printf("process over. trace_id=%s\n", traceId)
86     } else {
87         fmt.Printf("process over. no trace_id\n")
88     }
89     return
90 }

 

posted on 2022-06-05 18:20  啊哈好223  阅读(178)  评论(0)    收藏  举报