当前位置: 首页 > 科技观察

Golang语言中如何使用Context

时间:2023-03-11 21:14:02 科技观察

01。简介在Golang语言并发编程中,我们经常会遇到监听goroutine运行结束的场景。通常我们会想到使用WaitGroup和chan+select,其中WaitGroup用于监控一组goroutines是否完成所有操作,chan+select用于监控一个goroutine是否完成(取消一个goroutine)。如果我们需要监控是否有多个goroutines在运行(取消多个goroutines),我们通常使用context。当然,usingcontext也可以用来监控一个goroutine是否在运行(取消一个goroutine)。我们在之前的文章中介绍过Golang语言标准库Context,还没有阅读过的读者可以点播阅读。在本文中,我们主要介绍Context的一些使用方法。02.取消一个goroutine使用context取消一个goroutine,类似于使用chan+select取消一个goroutine。示例代码:funcmain(){ctx,cancel:=context.WithCancel(context.Background())gofunc(ctxcontext.Context){for{select{case<-ctx.Done():fmt.Println("goroutinestopped")返回默认值:fmt.Println("goroutineisrunning")time.Sleep(time.Second)}}}(ctx)time.Sleep(time.Second*5)cancel()time.Sleep(time.Second*5)fmt.Println("maingoroutinehasended")}阅读上面的代码,我们首先使用context.Background()创建一个上下文树的根节点,然后使用context.WithCancel()创建一个可取消的子上下文类型变量ctx,作为参数传递给子goroutine,用于跟踪子goroutine。然后在子goroutine中使用forselect监听<-ctx.Done()判断子goroutine是否执行完毕。最后,使用CancelFunc类型的取消变量,即context.WithCancel()返回的第二个值,将取消命令发送到子goroutine。03.取消多个goroutine接下来我们看一个使用context来停止多个goroutine的例子。funcmain(){ctx,cancel:=context.WithCancel(context.Background())//停止多个goroutinesgoworker(ctx,"节点一")goworker(ctx,"节点二")goworker(ctx,"节点三")time.Sleep(time.Second*5)cancel()time.Sleep(time.Second*5)fmt.Println("主程序已经结束")}funcworker(ctxcontext.Context,nodestring){for{select{case<-ctx.Done():fmt.Println(node,"goroutineisstopped")returndefault:fmt.Println(node,"goroutineisrunning")time.Sleep(time.Second)}}}阅读上面的代码,我们使用go关键字来启动三个workergoroutine。和前面的例子一样,先创建context树的根节点,使用返回值context类型的第一个子ctx来跟踪每个workergoroutine,在worker中使用forselect来监控<-ctx.Done()判断子goroutine是否运行完毕,最后通过调用第二个返回值CancelFunc类型的cancel向子goroutine发送取消命令。此时所有子上下文都会收到取消命令,goroutine结束。04.上下文信息传递我们在前面的例子中使用了WithCancel函数来取消上下文。另外,可以用来取消Context的函数还有WithDeadline函数和WithTimeout函数,分别用于定时取消和超时取消。本文篇幅不再赘述。有兴趣的读者可以参考官方的标准库文档。除了上面三个函数之外,还有一个WithValue函数,它是用来传递上下文信息的函数。在Golang语言中,Context包对于传递上下文信息也起着重要的作用。接下来介绍如何使用WithValue函数传递上下文信息。示例代码:funcmain(){ctx,cancel:=context.WithCancel(context.Background())//传递上下文信息ctxValue:=context.WithValue(ctx,"uid",1)gofunc(ctxcontext.Context){for{select{case<-ctx.Done():fmt.Println(ctx.Value("uid"),"goroutinehasstopped")returndefault:fmt.Println("goroutineisrunning")time.Sleep(time.Second)}}}(ctxValue)time.Sleep(time.Second*5)cancel()time.Sleep(time.Second*5)fmt.Println("maingoroutinehasended")}看上面的代码,我们使用WithValue该函数将上下文信息uid传递给子goroutine。WithValue函数接收三个参数,分别是父上下文、键和值。返回值是一个context,我们可以在子goroutine中调用Value方法来获取传递过来的context信息。05.总结在这篇文章中,我们简单介绍了几种监控goroutines的方法,即WaitGroup、chan+select和context。重点介绍context的一些使用方法,即取消一个goroutine,取消多个goroutine,传递context信息。关于定时取消和超时取消,有兴趣的读者可以参考官方的标准库文档。