go之Context(一)

Go语言中的Context

Context 是 Go 语言中非常重要的一个功能,它可以有效地传递请求的截止时间,以及请求的上下文(请求中包含的元数据)等信息。Context 是 Go 语言中超时设置、取消信号传递、goroutine 间数据传递等功能的重要组成部分。

在下面的文章中,我们将了解如何在 Go 语言中使用 Context
基本用法
在 Go 语言中,Context 被定义为一个接口类型,它包含了三个方法:

基本用法

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key any) any
}
  1. Deadline() 方法用于获取 Context 的截止时间,
  2. Done() 方法用于返回一个只读的 channel,用于通知当前 Context 是已否经被取消
  3. Err() 方法用于获取 Context 取消的原因,
  4. Value() 方法用于获取 Context 中保存的键值对数据。

Context 的基础知识

Context 表示一个运行环境中的请求,它是传递请求中的元数据(例如截止时间、取消信号、请求传递的值等)的机制。Context 中包含一个 Done 通道,可以用来在请求被取消或者超时时通知相关的 goroutine 停止处理请求工作。

在初始化 Context 时,我们可以使用 context.Background() 来创建一个根 Context,然后使用 WithCancelWithDeadlineWithTimeout 或者 WithValue 等函数来创建派生的 Context

这里有一些关于 Context 的一般使用规则:

  1. 不要将 Context 保存在结构体中,而是应该将其作为函数参数传递。
  2. Context 应该优先使用在请求的级别上,如在函数之间传递它,而不是在其他类型的代码之间传递它。
  3. 不要向不知情的代码中传递 nilContext,应该使用 context.TODO() 表示不确定的 Context

使用 Context 控制 goroutine

使用 WithContext 函数,可以将传递的 Context 对象传递给 goroutine 的启动函数,从而把 Context 对象传递到新启动的 goroutine 中。

使用 WithCancel() 取消goroutine操作

例如:

func myFunc(ctx context.Context) error {
    select {
        case <-time.After(time.Second):
            fmt.Println("请求完成")
        case <-ctx.Done():
            fmt.Println("请求取消")
            return ctx.Err()
    }
}
 
func main(){
    ctx, cancel := context.WithCancel(context.Background())
    go myFunc(ctx)
    time.Sleep(time.Millisecond*1500)
    cancel()
    time.Sleep(time.Second)
}

main 函数中,创建了根 Context,然后使用 WithContextContext 对象传递到 myFunc 中。在这个例子中,myFunc 会等待 1 秒钟来完成请求,然后会检查 Context 是否已经取消。如果 Context 取消,程序将立即返回错误信息。

main 函数中,等待 1.5 秒,然后调用 cancel 函数来取消 Context 中的 goroutine。goroutine 检测到受到取消操作后,打印出请求取消的消息,并返回 context.Canceled 错误信息。

在此例子中,我们使用了 context.Background() 函数创建了根的 Context。它是所有 Context 对象的默认值,没有任何附加值。 WithCancel 函数返回一个新的 Context 对象和一个 cancel 函数,这个函数可以用来取消 Context 中运行的 goroutine。

使用WithTimeout()设置goroutine超时操作

使用 context.WithTimeout 可以创建在指定的 timeout 期限内取消 Context 的示例。例如,如果请求处理时间超过 2 秒钟,则会发生超时操作:

func myFunc(ctx context.Context) error {
    select {
    case <-time.After(time.Second):
        fmt.Println("请求完成")
    case <-ctx.Done():
        fmt.Println("请求取消")
        return ctx.Err()
    }
}

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
    defer cancel()
    go myFunc(ctx)
    time.Sleep(time.Millisecond * 1500)
    fmt.Println("在规定时间内完成请求")
}

在这个例子中,我们使用 context.WithTimeout 函数在根 Context 上创建一个新的 Context,并设置请求时间超时为 2 秒钟。在 main 函数中:

启动了一个 myFunc goroutine,并等待 1.5 秒钟。然后输出一个完成请求的消息,因为 myFunc 在 1 秒钟内完成了这个请求。这说明,尽管使用了超时的 Context,但是在请求完成之前已经完成,并没有进行超时处理。

使用 WithDeadline() 设置goroutine截止时间

在这个示例中,我们使用了 context.WithDeadline 函数来设置请求的截止时间:

func myFunc(ctx context.Context) error {
    select {
        case <-time.After(time.Second):
            fmt.Println("请求完成")
        case <-ctx.Done():
            fmt.Println("请求取消")
            return ctx.Err()
    }
}
 
func main(){
    d := time.Now().Add(time.Second * 2)
    ctx, cancel := context.WithDeadline(context.Background(), d)
    defer cancel()
    go myFunc(ctx)
    time.Sleep(time.Millisecond*1500)
    fmt.Println("在规定时间内完成请求")
    time.Sleep(time.Second)
}

在这个例子中,我们使用了 time.Now().Add 函数设置了 2 秒钟的截止时间,并使用 context.WithDeadline 函数来创建一个包含截止时间的新 Context。当超过这个截止时间,将会发生一个取消操作。

main 函数中,等待 1.5 秒钟并输出完成请求的消息,最后等待 1 秒钟,是为了让 myFunc 在截止时间到来时有足够的时间来处理并取消请求。如果 myFunc 在截止时间到来之前完成请求,程序就会正常结束。

使用WithValue()向goroutine传递值

Context 还可以用来传递值,它可以传递键值对形式的元数据。传递的值必须是线程安全的类型,例如 string 或者 int 等基本数据类型,或者其他可以被并发访问的结构体。

下面的示例中,我们将会使用 WithValue 函数传递整数值:

func myFunc(ctx context.Context) {
    v := ctx.Value("key")
    fmt.Println("值:", v)
}
 
func main(){
    ctx := context.WithValue(context.Background(), "key", 100)
    myFunc(ctx)
}

在这个例子中,我们使用 WithValue 函数传递一个整型值 100,在 myFunc 中,使用键 key 将值传递给 goroutine。由于使用了 WithValue 函数,该值可以通过 ctx.Value 来访问。

需要注意的是,context.Value 函数的性能较差,在传递大量数据时,应该使用其他方法。

总结

在本文中,我们介绍了 Go 语言中的 Context,它是一个重要的功能,可以用来传递请求截止时间、取消信号、元数据等信息。我们还介绍了 WithContextWithTimeoutWithDeadlineWithValue 函数,并展示了如何在不同场景下使用 Context

通过了解 Context 的基础知识和使用方法,我们可以更好地控制 goroutine,提高程序的可靠性和性能。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Go语言中的context包提供了一种在跨多个goroutine之间传递请求范围数据、取消信号和截止时间的方法。它是Go语言中处理并发和并行的重要工具之一。 Context类型是context包中的核心类型,它代表了一个请求的上下文。通过创建一个Context对象,我们可以在程序中传递请求相关的数据和信号。Context对象可以被用于控制goroutine的生命周期,以及在需要时取消或超时处理。 Context包含了一些重要的方法和属性,例如: 1. WithCancel(parent Context) (ctx Context, cancelFunc CancelFunc):创建一个可取消的Context,并返回一个取消函数。当调用取消函数时,所有从该Context派生的子Context都会被取消。 2. WithDeadline(parent Context, deadline time.Time) (ctx Context, cancelFunc CancelFunc):创建一个带有截止时间的Context。当截止时间到达时,所有从该Context派生的子Context都会被取消。 3. WithTimeout(parent Context, timeout time.Duration) (ctx Context, cancelFunc CancelFunc):创建一个带有超时时间的Context。当超过指定的时间后,所有从该Context派生的子Context都会被取消。 4. WithValue(parent Context, key interface{}, value interface{}) Context:创建一个带有键值对的Context。这个方法可以用来传递请求范围的数据。 使用context包可以有效地管理并发操作,避免资源泄漏和无限等待的情况。在编写并发代码时,合理使用context包可以提高程序的可读性和可维护性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值