go context

go context

context是go语言中用来在协程中传递数据的,也可以用来停止协程

1、数据传递

context可以传递各种数据,例如字节,字符串,结构体等等

使用Withvalue来设置键值对

package main

import (
	"context"
	"fmt"
)

type User struct {
	Name string
}


func main() {
    // 创建一个空的context
	ctx := context.Background()
    // 设置键值对
	ctx = context.WithValue(ctx, "name", "xiaoxie")
    
	ctx = context.WithValue(ctx, "user", User{
		Name: "xiaoyang",
	})
	GetUser(ctx)
}

func GetUser(ctx context.Context) {
    // 获取context中的键值对数据
	fmt.Println(ctx.Value("name"))
    // 可以进行断言处理
	fmt.Println(ctx.Value("user").(User).Name)
}

2、取消协程

在运行过程中,用户可能随时取消一个耗时的请求操作,所以我们需要提供给用户一个取消协程的接口

没有取消协程的操作只能等待

package main

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

var waitGroup = sync.WaitGroup{}

func main() {
	waitGroup.Add(1)
	t1 := time.Now()
	go func() {
		info, err := GetIP(context.Background())
		fmt.Println(info, err)
		waitGroup.Done()
	}()
	waitGroup.Wait()
	fmt.Println("执行完成", time.Since(t1))
}

func GetIP(ctx context.Context) (string, error) {
	// 模拟耗时的操作
	time.Sleep(4 * time.Second)
	// 模拟请求的内容
	return "localhost", nil
}

输出内容

localhost <nil>
执行完成 4.0064976s

实现取消协程

package main

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

var waitGroup = sync.WaitGroup{}

func main() {
	waitGroup.Add(1)
	ctx, cancel := context.WithCancel(context.Background())

	t1 := time.Now()
	go func() {
		info, err := GetIP(ctx)
		fmt.Println(info, err)
		waitGroup.Done()
	}()

	go func() {
		// 假设过了两秒用户取消协程
		time.Sleep(2 * time.Second)
		cancel()
	}()

	waitGroup.Wait()
	fmt.Println("执行完成", time.Since(t1))
}

func GetIP(ctx context.Context) (string, error) {
	// 监听
	go func() {
		select {
		case <-ctx.Done():
			err := ctx.Err()
			fmt.Println("协程取消", err)
			waitGroup.Done()
			return
		}
	}()


	time.Sleep(4 * time.Second)
	waitGroup.Done()

	return "localhost", nil
}

输出:

协程取消 context canceled
执行完成 2.003113s

3、截止时间、超时时间

context可以主动取消,也可以根据截止时间或者超时时间来取消

截止时间

设置一个截止的时间点

package main

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

var waitGroup = sync.WaitGroup{}

func main() {
	waitGroup.Add(1)
	ctx, cancel := context.WithDeadline(context.Background(), time.Now().Add(2*time.Second))
	defer cancel()
	t1 := time.Now()
	go func() {
		info, err := GetIP(ctx)
		fmt.Println(info, err)
		waitGroup.Done()
	}()

	waitGroup.Wait()
	fmt.Println("执行完成", time.Since(t1))
}

func GetIP(ctx context.Context) (string, error) {
	// 监听
	go func() {
		select {
		case <-ctx.Done():
			err := ctx.Err()
			fmt.Println("截止时间已到", err)
			waitGroup.Done()
			return
		}
	}()

	// 模拟耗时的操作
	time.Sleep(4 * time.Second)
	waitGroup.Done()
	// 模拟请求的内容
	return "localhost", nil
}

截止时间已到 context deadline exceeded
执行完成 2.0086572s

超时时间

设置一个超时的时长,其余代码部分基本一致

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
posted @ 2025-03-28 19:05  小依昂阳  阅读(32)  评论(0)    收藏  举报