前言
编码中遇到上下文信息传递,并发信息取消等,记录下在go语言中context包的使用。
context 介绍
在Go语言中,context包提供了一种在程序中传递截止日期、取消信号、请求范围数据和其他元数据的方式。context包的核心类型是Context接口,它定义了在执行上下文中传递的方法。Context接口的主要方法包括Deadline、Done、Err、Value等。
关键概念和使用方式
-
Background:
context.Background()
函数返回一个空的Context
,通常作为整个应用的顶层上下文,用于传递全局的信息。 -
WithCancel:
context.WithCancel
函数创建一个带有取消信号的Context
。当调用返回的cancel
函数时,与该Context
相关联的所有操作都会被取消。ctx, cancel := context.WithCancel(context.Background()) defer cancel() // 在不再需要时调用cancel
-
WithTimeout和WithDeadline:
context.WithTimeout
和context.WithDeadline
函数创建带有截止日期的Context
。WithTimeout
设置相对于当前时间的截止日期,而WithDeadline
设置绝对时间的截止日期。ctx, cancel := context.WithTimeout(context.Background(), time.Second*10) defer cancel() // 在不再需要时调用cancel
-
WithValue:
context.WithValue
函数可以在Context
中存储键值对,用于传递请求范围的数据。但要注意,过度使用WithValue
可能导致上下文变得复杂,应慎重使用。ctx := context.WithValue(context.Background(), key, value)
-
Done和Err:
Done
通道会在上下文被取消或达到截止日期时关闭。Err
方法返回取消的原因,通常是context.Canceled
或context.DeadlineExceeded
。select { case <-ctx.Done(): // 上下文被取消 fmt.Println("Context canceled:", ctx.Err()) }
context
包的设计旨在简化在不同部分之间传递截止日期、取消信号和请求范围数据的方式,特别是在并发环境中。使用context
包可以更好地管理资源、控制执行时间和处理取消操作。
基础使用
基础的context
包使用示例,演示如何创建上下文、设置截止日期、取消上下文等基本操作:
package main
import (
"context"
"fmt"
"time"
)
func main() {
// 创建一个带有取消信号的上下文
ctx, cancel := context.WithCancel(context.Background())
// 启动一个goroutine执行任务,并传入上下文
go performTask(ctx)
// 模拟等待用户输入或其他触发条件
fmt.Println("Press Enter to cancel the task.")
fmt.Scanln()
// 调用cancel函数取消上下文
cancel()
// 等待一段时间,以确保goroutine有足够的时间处理取消操作
time.Sleep(time.Second * 2)
}
func performTask(ctx context.Context) {
// 使用select监听上下文的取消信号
select {
case <-ctx.Done():
// 当上下文被取消时执行的操作
fmt.Println("Task canceled:", ctx.Err())
default:
// 模拟一个长时间运行的任务
for i := 1; i <= 5; i++ {
fmt.Println("Task is running...")
time.Sleep(time.Second)
}
fmt.Println("Task completed successfully.")
}
}
在这个示例中,我们首先创建一个带有取消信号的上下文,然后启动一个goroutine执行performTask
函数。用户在控制台输入任意字符后,我们调用cancel
函数取消上下文。performTask
函数中使用select
监听上下文的取消信号,一旦上下文被取消,任务将提前结束。在实际应用中,可以根据需要设置截止日期、传递数据等,以更灵活地管理上下文。
进阶使用
进阶的复杂示例,演示如何使用context
包处理多个并发任务,并在某个任务失败或超时时取消所有任务:
package main
import (
"context"
"fmt"
"math/rand"
"sync"
"time"
)
func main() {
// 创建一个带有取消信号的上下文,设置总体超时为5秒
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
defer cancel()
// 使用WaitGroup等待所有任务完成
var wg sync.WaitGroup
// 启动多个goroutine执行任务
for i := 1; i <= 3; i++ {
wg.Add(1)
go performTask(ctx, i, &wg)
}
// 等待所有任务完成或上下文取消
wg.Wait()
fmt.Println("All tasks completed.")
}
func performTask(ctx context.Context, taskID int, wg *sync.WaitGroup) {
defer wg.Done()
// 模拟每个任务的执行时间
taskDuration := time.Second * time.Duration(rand.Intn(10))
fmt.Printf("Task %d started. Duration: %s\n", taskID, taskDuration)
// 使用WithTimeout创建一个子上下文,设置每个任务的超时时间
subCtx, cancel := context.WithTimeout(ctx, taskDuration)
defer cancel()
select {
case <-subCtx.Done():
// 当子上下文被取消时执行的操作
if subCtx.Err() == context.DeadlineExceeded {
fmt.Printf("Task %d timed out.\n", taskID)
} else {
fmt.Printf("Task %d canceled.\n", taskID)
}
case <-time.After(taskDuration):
// 模拟任务的实际工作
fmt.Printf("Task %d completed successfully.\n", taskID)
}
}
在这个示例中,我们创建了一个带有总体超时的上下文,并启动了多个goroutine执行performTask
函数。每个任务都有一个随机的执行时间,并在子上下文中设置了超时。使用select
监听子上下文的取消信号,一旦有任务失败或超时,它将及时结束。通过使用sync.WaitGroup
等待所有任务完成,我们确保在所有任务完成或总体超时后程序可以退出。文章来源:https://www.toymoban.com/news/detail-813033.html
这种方式可以更好地控制并发任务,确保及时释放资源并在需要时取消任务。在实际应用中,可以根据具体需求调整超时时间和处理逻辑。文章来源地址https://www.toymoban.com/news/detail-813033.html
到了这里,关于golang中context详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!