Go语言的Context是一个接口类型,用于跟踪请求作业的状态并在各个Goroutine之间传递值和取消信号。Context是Goroutine之间传递参数的一种更好的方式。它提供了短时间的存储,可用于同一请求处理中的一串Goroutine之间的信号,通知,和元数据。
Context的主要方法包括WithValue, Deadline, 和 Done以及Err
1. WithValue()方法:
WithValue方法用于创建一个派生Context,并将键值对存储在上下文中。它的作用是在上下文中设置一些公共的数据,在Goroutine之间共享。WithValue的返回值是一个新的上下文(新对象),并使用新值创建一个传递的键,它保存在上下文树中,并对后代GORoutine可见。
2. Deadline()方法:
Deadline方法返回与上下文关联的截止时间(时间窗口),当当前时刻超过截止时间时,上下文的Done()方法会被关闭。Deadline方法返回两个值:截止时间和一个布尔值。如果有截止时间,ok值将为真,否则它为false。
3. Done()方法:
Done方法返回一个只要上下文被取消或过期都会关闭的只读chan。如果上下文超过它的截止时间或它的父上下文被取消或过期,它会关闭自己的Done()方法。Done()方法作为一个广播机制,用于从可能多于一个Goroutine的地方取消执行上下文。所以,每次在一个新的Goroutine中调用时,需要新建一个子上下文。
4. Err()方法:
Err方法返回上下文被取消的原因的错误值。如果上下文没有被取消,它将返回nil。当上下文取消时,因为未完成的工作超过了context.WithDeadline,context.WithTimeout等设置的截止时间,或者因为父上下文被取消而取消时,Err会传递取消原因进行关闭。
一个简单的示例:
“`go
package main
import (
"context"
"fmt"
"time"
)
func main() {
parent := context.Background()
ctx, cancel := context.WithCancel(parent)
go func() {
time.Sleep(time.Second)
cancel()
}()
select {
case <-time.After(3 * time.Second):
fmt.Println("Timeout exceeded")
case <-ctx.Done():
fmt.Println("Context Cancelled")
}
ctx, cancel = context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
select {
case <-time.After(time.Second):
fmt.Println("Sleep complete")
case <-ctx.Done():
fmt.Println("Context Cancelled")
}
}
“`
上面的代码中,我们使用context.Background()函数创建一个根上下文parent。WithContext函数创建了一个新的上下文ctx及与其关联的取消函数cancel。接下来,在其中启用一个另外的Goroutine,等待1秒后再取消上下文。
在主程序的第一个select语句中,等待3秒钟,并在Done通道关闭时通知退出。在这里,由于上下文被取消,我们通过ctx.Done()情况回来,最后,我们使用context.WithTimeout()创建了另一个上下文,并通过一个select语句监测它的上下文,并在Done通道关闭时通知退出。这里同样证明了上下文在其过期时间到期时会自动关闭。