go-doc-context

Background()

这个函数返回一个空 context。这只能用于高等级(在 main 或顶级请求处理中)。通常用于派生的其他 context 。

TODO()

这个函数也是创建一个空 context。也只能用于高等级或当您不确定使用什么 context,或函数以后会更新以便接收一个 context 。这意味您(或维护者)计划将来要添加 context 到函数。

它与 background 完全相同。不同的是,静态分析工具可以使用它来验证 context 是否正确传递,这是一个重要的细节,因为静态分析工具可以帮助在早期发现潜在的错误,并且可以连接到 CI/CD 管道。

WithValue()

此函数接收 context 并返回派生 context,其中值 val 与 key 关联,并通过 context 树与 context 一起传递。这意味着一旦获得带有值的 context,从中派生的任何 context 都会获得此值。不建议使用 context 值传递关键参数,而是函数应接收签名中的那些值,使其显式化。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package main

import (
"context"
"fmt"
)

func main() {
ctx := context.WithValue(context.Background(), "trace_id", "88888888")
// 携带session到后面的程序中去
ctx = context.WithValue(ctx, "session", 1)

process(ctx)
}

func process(ctx context.Context) {
session, ok := ctx.Value("session").(int)
fmt.Println(ok)
if !ok {
fmt.Println("something wrong")
return
}

if session != 1 {
fmt.Println("session 未通过")
return
}

traceID := ctx.Value("trace_id").(string)
fmt.Println("traceID:", traceID, "-session:", session)
}

WithCancel()

返回派生 context 和取消函数。只有创建它的函数才能调用取消函数来取消此 context。如果您愿意,可以传递取消函数,但是,强烈建议不要这样做。这可能导致取消函数的调用者没有意识到取消 context 的下游影响。可能存在源自此的其他 context,这可能导致程序以意外的方式运行。简而言之,永远不要传递取消函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithCancel(context.Background())
flags := checkFlag(ctx)
for n := range flags {
if n >= 10 {
cancel()
fmt.Println("main 进行 chanel()")
break
}
}

fmt.Println("main chanel()以后")
time.Sleep(2 * time.Second)
}

func checkFlag(ctx context.Context) <-chan int {
c := make(chan int)
n := 0
go func() {
for {
select {
case <-ctx.Done():
fmt.Printf("checkFlag函数 Done()\n")
return
case c <- n:
n++
fmt.Printf("系数加1\n")
}
}
}()

return c
}

WithDeadline()

此函数返回其父项的派生 context,当截止日期超过或取消函数被调用时,该 context 将被取消。例如,您可以创建一个将在以后的某个时间自动取消的 context,并在子函数中传递它。当因为截止日期耗尽而取消该 context 时,获此 context 的所有函数都会收到通知去停止运行并返回。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(time.Second * 2))
defer cancel()

flags := checkFlag(ctx)

select {
case <-ctx.Done():
fmt.Printf("main 挂起2秒后,值加到了 %d\n", <-flags)
}

fmt.Println("main chanel()以后")
time.Sleep(3 * time.Second)
}

func checkFlag(ctx context.Context) <-chan int {
c := make(chan int)
n := 0
go func() {
for {
time.Sleep(time.Millisecond * 100)
select {
case <-ctx.Done():
c<-n
fmt.Printf("checkFlag函数 Done()\n")
return
default :
n++
fmt.Printf("系数加1\n")
}
}
}()

return c
}

WithTimeout()

此函数类似于 context.WithDeadline。不同之处在于它将持续时间作为参数输入而不是时间对象。此函数返回派生 context,如果调用取消函数或超出超时持续时间,则会取消该派生 context。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package main

import (
"context"
"fmt"
"time"
)

func main() {
ctx, cancel := context.WithTimeout(context.Background(), time.Second * 2)
defer cancel()

flags := checkFlag(ctx)

select {
case <-ctx.Done():
fmt.Printf("main 挂起2秒后,值加到了 %d\n", <-flags)
}

fmt.Println("main chanel()以后")
time.Sleep(3 * time.Second)
}

func checkFlag(ctx context.Context) <-chan int {
c := make(chan int)
n := 0
go func() {
for {
time.Sleep(time.Millisecond * 100)
select {
case <-ctx.Done():
c<-n
fmt.Printf("checkFlag函数 Done()\n")
return
default :
n++
fmt.Printf("系数加1\n")
}
}
}()

return c
}