golang Context语法解析
本文最后更新于19 天前,其中的信息可能已经过时,如有错误请留言

一、context是什么

context是标准库的接口

type Context interface {
	Deadline() (deadline time.Time, ok bool)
	Done() <-chan struct{}
	Err() error
	Value(key any) any
}

Deadline方法

设置context.Context的取消时间,即截止时间

Done方法

返回一个只读channel,当context被取消或者到达截止时间,channel就会被关闭,表示context的链路结束,多次调用Done方法会返回同一个channel

Err方法

返回context.Context结束的原因,它只会在Done返回的Channel被关闭时,才会返回非空的值,返回值有以下两种情况

  • 如果是context.Context被取消,返回Cancelled
  • 如果是context.Context超时,返回DeadlineExceeded

Value方法

从context.Context中获取键对应的值

对于同一个Context,多次调用Value并传入相同的Key会返回相同的结果,如果没有对应的key,则返回nil

键值对是通过WithValue方法写入的

二、context创建

1、根context创建

有两种方式创建根context

  • context.Background()
  • context.TODO()

根context是一个空的context

如果当前函数没有context作为入参,又需要context来传递上下文,一般会创建一个根context,作为起始的上下文往下传递

2、根context传递上下文

根context没有实质功能,为了能够传递上下文,需要依赖于With系列函数

with系列函数会派生出新的context(创建出新的context)

主要的With系列函数如下

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)​
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
​func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
​func WithValue(parent Context, key, val interface{}) Context

基于当前context,每个with函数都会创建出一个新的context,这样类似于我们熟悉的树结构,当前context称为父context,派生出的新context称为子context。就像下面的context树结构:

通过根context,通过四个with系列方法可以派生出四种类型的context,每种context又可以通过同样的方式调用with系列方法继续向下派生新的context,整个结构像一棵树。

三、context作用

context主要有两个用途

  • 上下文信息传递
  • 用于并发控制,控制协程优雅退出

上下文信息传递

context中可以携带多个键值对,用于上下文信息的传递,例如请求id,以及trace_id等,用于链路追踪,以及配置透传

package main

import (
	"context"
	"fmt"
	"sync"
)

var wg sync.WaitGroup

func main() {
	ctx := context.WithValue(context.Background(), "age", 18)
	ctx = context.WithValue(ctx, "name", "zhang")
	wg.Add(1)
	go func(ctx context.Context) {
		defer wg.Done()
		fmt.Printf("name: %v\n", ctx.Value("name").(string))
		fmt.Printf("age: %v\n", ctx.Value("age").(int))
	}(ctx)
	wg.Wait()
}

输出如下

name: zhang
age: 18

并发控制

context.WithCancel

func WithCancel(parent Context) (ctx Context, cancel CancelFunc)

返回的cancel执行后,ctx.Done方法返回的channel会收到信号,示例如下

package main

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

var wg sync.WaitGroup

func main() {
	ctx, cancelFunc := context.WithCancel(context.Background())
	wg.Add(2)
	go Watch(ctx, "goroutine1")
	go Watch(ctx, "goroutine2")
	time.Sleep(4 * time.Second)
	fmt.Println("cancel watching")
	cancelFunc()
	wg.Wait()
}

func Watch(ctx context.Context, name string) {
	defer wg.Done()
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name, " exit!")
			return
		default:
			fmt.Println(name, " waiting.")
			time.Sleep(1 * time.Second)
		}
	}
}

context.WithDeadline

在WithCancel的基础上可以设置绝对时间来控制取消,到了指定的时间相当于会自动执行cancel函数

ctx, cancel := context.WithDeadline(context.Background(),time.Now().Add(4*time.Second))

context.WithTimeout

在WithCancel的基础上可以设置相对时间来控制取消,超过一定时间后,会自动执行cancel函数,Done方法返回的channel会收到一个信号

ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)

感谢阅读!如有疑问请留言
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇