Golang

关注公众号 jb51net

关闭
首页 > 脚本专栏 > Golang > go中context的使用

go语言中context的使用说明

作者:编程砖家

Go语言中的Context是用于在多个函数或goroutine之间传递取消信号、超时控制、截止时间和请求范围数据的重要概念,它提供了更好的控制和管理,适用于并发编程中需要传递状态或进行资源清理的场景

概述

Context 是 Go 语言中非常重要的一个概念,它主要用于跨多个函数或 goroutine 传递 取消信号超时控制截止时间请求范围数据

在并发编程中,Context 提供了更好的控制和管理,尤其是当你需要在多个 goroutine 之间传递状态或进行资源清理时。

主要功能

Context 主要有以下几个功能:

Context 的三种基本类型

Go 中的 context 包提供了几种常用的 Context 类型:

常见用法举例

context.WithCancel传递取消信号

主要场景:

代码示例:

package main

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

func main() {
	// 创建一个可取消的 Context
	ctx, cancel := context.WithCancel(context.Background())

	// 启动一个 goroutine,监听取消信号
	go func(ctx context.Context) {
		for {
			select {
			case <-ctx.Done(): // 检测到取消信号
				fmt.Println("Goroutine stopped")
				return
			default:
				// 模拟工作
				fmt.Println("Working...")
				time.Sleep(1 * time.Second)
			}
		}
	}(ctx)

	// 主线程等待 3 秒后取消
	time.Sleep(3 * time.Second)
	cancel() // 发送取消信号

	// 等待 goroutine 退出
	time.Sleep(1 * time.Second)
	fmt.Println("Main program exited")
}

解释

  1. 主线程创建了一个带有取消功能的上下文 ctx
  2. 子 goroutine 使用 ctx.Done() 监听取消信号。
  3. 主线程 3 秒后调用 cancel(),子 goroutine 检测到信号后优雅退出。

使用 WithTimeout 设置超时

context.WithTimeout 用于设置一个超时时间,超过该时间后 Context 会自动取消,适用于需要限时执行的操作。防止某些任务阻塞的时间过长。

package main

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

func main() {
	// 设置超时时间为 2 秒
	ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
	defer cancel() // 确保超时后取消 ctx

	// 启动一个模拟长时间执行的任务
	go longRunningTask(ctx)

	// 等待超时或任务完成
	<-ctx.Done()
	if ctx.Err() == context.DeadlineExceeded {
		fmt.Println("Timeout reached")
	}
}

func longRunningTask(ctx context.Context) {
	select {
	case <-time.After(3 * time.Second): // 模拟长时间任务
		fmt.Println("Task completed")
	case <-ctx.Done():
		// 任务被取消或超时
		fmt.Println("Task cancelled due to timeout")
	}
}

WithDeadline的用法和Withtimeout用法类似,只是一个传入的参数是等待时间,一个传入的参数是截止时间。

使用 WithValue 传递数据

context.WithValue 可以在 Context 中存储键值对,通常用于传递请求级别的数据(例如用户身份、请求 ID 等)。

package main

import (
	"context"
	"fmt"
)

func main() {
	// 创建一个上下文并传递数据
	ctx := context.WithValue(context.Background(), "userID", 12345)

	// 将 ctx 传递给其他函数
	processRequest(ctx)
}

func processRequest(ctx context.Context) {
	// 从 ctx 中提取数据
	userID := ctx.Value("userID")
	if userID != nil {
		fmt.Println("User ID:", userID)
	} else {
		fmt.Println("No user ID found")
	}
}

使用 WithValue 小心context.WithValue 并不是用于传递大量数据的,主要用于传递少量的上下文信息,比如请求 ID 等。

如果传递过多的数据,会使得 Context 难以维护。

常用的相关方法和常量

context如何控制goroutine的执行

从上面的举例可以看出,在每个goroutine中通过判断ctx.Done()是否被执行,从而知道任务是否被取消/超时/到达截止日期。

Context 被取消(调用 cancel())或超时/到达截止时间时,ctx.Done() 所关联的 channel 会关闭,此时select语句就可以执行ctx.Done()对应的分支。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

您可能感兴趣的文章:
阅读全文