go context上下文
1、context 的解释
在 API 之间或者方法调用之间,传递的除了业务参数之外的其他信息,比如 traceId 等。
比如,服务端接收到客户端的 HTTP 请求之后,可以把客户端的 IP 地址和端口、客户端的身份信息、请求接收的时间、Trace ID 等信息放入到上下文中,这个上下文可以在后端的方法调用中传递,后端的业务方法除了利用正常的参数做一些业务处理(如订单处理)之外,还可以从上下文读取到消息请求的时间、Trace ID 等信息,把服务处理的时间推送到 Trace 服务中。Trace 服务可以把同一 Trace ID 的不同方法的调用顺序和调用时间展示成流程图,方便跟踪。
2、context 的作用
- 上下文信息传递
- 控制子协程的运行
- 超时控制的方法调用
- 可以取消的方法调用
3、应用场景
上下文信息传递,WithValue 的应用
package main
import (
"context"
"fmt"
"time"
)
func main() {
// 父上下文
ctx := context.Background()
setValue(ctx)
}
func process(ctx context.Context) {
name, ok := ctx.Value("name").(string)
if ok {
fmt.Printf("process over. name=%s\n", name)
} else {
fmt.Printf("process over. no name\n")
}
}
func setValue(ctx context.Context) {
process(ctx)
// 为上下文设置key value
ctx = context.WithValue(ctx, "name", "liu")
process(ctx)
}
go run context1.go
process over. no name
process over. name=liu
控制子协程的运行,WithCancel 应用
当系统中有耗时任务时,如果想控制子协程的生命周期可以在主协程调用 cancel 函数,结束子协程的运行。
前提是子协程中对 ctx.Done()做了监听
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx := context.Background()
cancelGoroutine(ctx)
}
func cancelGoroutine(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("主协程处理结束,子协程结束...")
return
case <-time.After(time.Second):
fmt.Println("处理耗时任务...")
}
}
}()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
fmt.Println("主协程处理逻辑...")
time.Sleep(5 * time.Second)
cancel()
time.Sleep(1 * time.Second)
}
go run context1.go
主协程处理逻辑...
处理耗时任务...
处理耗时任务...
处理耗时任务...
处理耗时任务...
主协程处理结束,子协程结束...
超时控制,WithTimeout 的应用
package main
import (
"context"
"fmt"
"time"
)
func main() {
ctx := context.Background()
cancelGoroutine(ctx)
}
func cancelGoroutine(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
fmt.Println("主协程处理超时,子协程结束...")
return
case <-time.After(time.Second):
}
}
}()
ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
defer cancel()
fmt.Println("主协程处理逻辑...")
time.Sleep(5 * time.Second)
}
go run context1.go
主协程处理逻辑...
主协程处理超时,子协程结束...