首页 > 编程知识 正文

golang context 使用用法介绍

时间:2023-11-20 00:13:53 阅读:288817 作者:TGEB

本文将详细介绍在进行golang编程过程中如何更好地使用context。对于初学者来说,context可能是一件比较抽象的事情,但是,对于一些高级开发者,context则是非常重要的工具。因此,在本文中,我们将从以下几个方面进行详细解释:

一、 context的基础知识

首先,我们需要了解context的一些基础知识。Context 区别于 类 Unix系统的环境变量或者进程之间传递信息的方式,Go 源码中和项目本身代码传递信息、超时信号的重要途径。在Go 的Concurrent环境下,从一个协程传递信息(比如超时信号、Cancel 信号、传递值等)给另外一个协程变得非常地困难。这时候Context就派上用场了,它提供了一个机制,子 goroutine 可以继承其父 goroutine 的 Context,只需要在 Context 实例中进程所需要的一些参数、信息等,就可以轻松地将其传递给其他子 goroutine 了。

下面来看一下context的使用方法:

// 创建一个context.Context对象
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)

// 通过context对象控制超时时间
var wg sync.WaitGroup
go func() {
   select {
   case <-time.After(3 * time.Second):
       fmt.Println("超时3秒")
       // 超时后,取消程序
       cancel()
   case <-ctx.Done():
       fmt.Println(ctx.Err())
   }
}()

wg.Wait()

上面的代码演示了如何通过context实现程序的超时控制,如果程序在3秒钟内没有执行完成,就会被我们的context对象取消掉。其中,context.Background() 函数用来创建一个空的 Context, context.WithCancel() 函数则是生成了一个新的 Context,同时在该 Context 被取消时调用 context.CancelFunc() 函数。在该例子中,我们使用Context控制goroutine的执行时间,如果超时,就会取消其中的协程。这样,我们就可以实现控制代码的执行时间的功能。

二、 context的使用方法

除了上述的例子,我们还可以使用context实现一些其他的操作,比如goroutine之间的信息传递。下面我们将通过实例来说明如何使用context实现goroutine之间的信息传递:

package main

import (
    "context"
    "fmt"
)

func main() {
    // 创建根Context
    rootContext := context.Background()

    // 创建一个子Context
    childContext, childCancel := context.WithCancel(rootContext)

    // 子协程
    go childFunc(childContext)

    // 等待子协程执行完毕
    <-childContext.Done()

    // 取消子协程
    childCancel()
}

func childFunc(ctx context.Context) {
    // 从ctx中得到值
    value := ctx.Value("key")

    // 输出值
    fmt.Println("value:", value)

    // 取出值
    child := context.WithValue(ctx, "child", "child value")

    // 通过child context传递信息
    fmt.Println("child:", child.Value("child"))
}

从上面的代码中,我们可以看到,通过context,我们可以很好地实现goroutine之间的信息传递。可以看到,我们通过context对象创建了两个goroutine,一个主goroutine,一个子goroutine。接着,我们通过context对象在子goroutine中传递了信息。这个信息可以是一个简单的值,也可以是一个更加复杂的结构体。对于使用过Golang中goroutine的人都应该知道Golang中的这种并发会比线程简单的多,这也证明了其优秀性,在高并发访问原来没有任何问题的单机部署的时候也会出现问题,有时则需要不同的处理方式以便最终能够取得令人满意的性能。

三、 context的注意事项

虽然context是一种非常重要的工具,但是,在使用这个工具的时候,我们需要注意一些问题。下面,我们将从以下几个方面详细讲解:

1.不要把context保存在结构体中

当我们使用context的时候,我们需要注意一些问题。首先,我们需要格外小心context作用域。在使用context的时候,我们不应该将context对象保存在结构体中。如果我们将context保存在结构体中,那么我们就很有可能会在不同的函数中使用同一个context对象,从而导致出现一些未知的问题。

下面是一个例子:

func main() {
    ctx := context.Background()
    foo(ctx)
    bar(ctx)
}

func foo(ctx context.Context) {
    // Do some work
}

func bar(ctx context.Context) {
    // Do some other work
}

在上面的例子中,我们创建了一个context对象,并将其传递给两个不同的函数。因为context对象的作用域是很短的,所以我们不会出现什么问题。但是,如果我们将context对象保存在结构体中,那么在不同的函数中使用同一个context对象,就会导致出现一些不可预知的问题。

2.永远不要传递空的context

另外,我们还需要注意一些其他的问题。比如,我们在使用context的时候,永远不要传递空的context。因为空的context对象虽然不会报错,但是会导致程序出现问题。这是因为,传递空的context对象会导致在一些子函数中出现使用了空的context对象的情况,从而导致不可预知的结果。因此,在使用context的时候,我们需要格外注意,不要传递空的context对象。

3.不要在HTTP请求中使用context超时

最后,我们需要注意一些其他的问题。在使用context的时候,我们需要格外注意一些问题。比如,在HTTP请求中使用context超时是很危险的。因为在HTTP请求中,如果设置了一个太短的超时时间,那么当服务器负载过高时,就会导致大量的请求失败,从而引起一些不可预知的问题。因此,在使用context超时的时候,我们需要格外小心,不要设置一个太短的时间。

四、 代码示例

上面的描述只是为了介绍context的基础知识以及注意事项。同时,在实际开发代码的时候,context的使用也有很多更加高级的应用。最后,我们为大家呈现一个简单的代码示例,供大家参考:

// main.go
package main

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

// 执行任务的函数
func doTask(ctx context.Context, wg *sync.WaitGroup) error {
    defer wg.Done()

    for {
        select {
        case <-ctx.Done():
            // context被取消了
            fmt.Println("退出 doTask,原因:", ctx.Err())
            return ctx.Err()
        default:
            // 模拟任务执行
            time.Sleep(time.Second)
            fmt.Println("doTask 执行一次...")
        }
    }
}

func main() {
    fmt.Println("主程序启动了...")
    fmt.Println("")

    // 创建Context
    ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
    defer cancel()

    // WaitGroup,可以方便我们等待goroutine执行完毕
    wg := &sync.WaitGroup{}

    // 启动goroutine
    wg.Add(1)
    go doTask(ctx, wg)

    // 等待goroutine执行完毕
    wg.Wait()

    fmt.Println("")
    fmt.Println("主程序退出了...")
}

上面的这个代码示例中,我们引入了“WaitGroup”的概念。WaitGroup 可以用来等待一组 goroutine 的结束。主程序使用WaitGroup来等待“doTask”协程的结束。"doTask"协程是这个程序的核心。在这个协程中,我们模拟了一个长时间运行的任务。通过 “ctx” 变量,程序可以监控任务何时结束,以便及时退出程序。

总结

本文详细介绍了golang中的context的使用方法。我们从context基础知识的介绍开始,然后逐步深入讲解了context的使用方法和注意事项。最后,我们为大家呈现了一个简单的代码示例,供大家参考。通过本文的学习,相信大家已经掌握了golang中context的基本知识和使用方法,可以在实际项目开发中运用自如了。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。