脚本之家,脚本语言编程技术及教程分享平台!
分类导航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服务器之家 - 脚本之家 - Golang - Golang 语言中 Context 的使用方式

Golang 语言中 Context 的使用方式

2021-04-29 00:52Golang语言开发栈frank Golang

在 Golang 语言并发编程中,经常会遇到监控 goroutine 运行结束的场景,通常我们会想到使用 WaitGroup 和 chan + select,其中 WaitGroup 用于监控一组 goroutine 是否全部运行结束,chan + select 用于监控一个 goroutine 是否运行结束(取消一个 goro

01、介绍

Golang 语言并发编程中,经常会遇到监控 goroutine 运行结束的场景,通常我们会想到使用 WaitGroup 和 chan + select,其中 WaitGroup 用于监控一组 goroutine 是否全部运行结束,chan + select 用于监控一个 goroutine 是否运行结束(取消一个 goroutine)。

Golang 语言中 Context 的使用方式

如果我们需要监控多个 goroutine 是否运行结束(取消多个 goroutine),通常会使用 context,当然使用 context 也可以用于监控一个 goroutine 是否运行结束(取消一个 goroutine)。我们在之前的文章已经介绍过 Golang 语言标准库 Context,未阅读的读者朋友们可以按需翻阅。本文我们主要介绍 Context 的一些使用方式。

02、取消一个 goroutine

使用 context 取消一个 goroutine,比较类似于使用 chan + select 的方式取消一个 goroutine。

示例代码:

  1. func main () { 
  2.  ctx, cancel := context.WithCancel(context.Background()) 
  3.  go func(ctx context.Context) { 
  4.   for { 
  5.    select { 
  6.     case <-ctx.Done(): 
  7.      fmt.Println("goroutine 已停止"
  8.      return 
  9.    default
  10.     fmt.Println("goroutine 正在运行"
  11.     time.Sleep(time.Second
  12.    } 
  13.   } 
  14.  }(ctx) 
  15.  time.Sleep(time.Second * 5) 
  16.  cancel() 
  17.  time.Sleep(time.Second * 5) 
  18.  fmt.Println("main goroutine 已结束"

阅读上面这段代码,我们首先使用 context.Background() 创建一个 context 树的根节点,然后使用 context.WithCancel() 创建一个可取消的子 context 类型的变量 ctx,作为参数传递给子 goroutine,用作跟踪子 goroutine。

然后在子 goroutine 中,使用 for select 监控 <-ctx.Done() 判断子 goroutine 是否运行结束。

最后使用 context.WithCancel() 返回的第二个值 CancelFunc 类型的 cancel 变量给子 goroutine 发送取消指令。

03、取消多个 goroutine

接下来,我们再来看一个使用 context 停止多个 goroutine 的示例。

  1. func main () { 
  2.  ctx, cancel := context.WithCancel(context.Background()) 
  3.   // 停止多个 goroutine 
  4.  go worker(ctx, "节点一"
  5.  go worker(ctx, "节点二"
  6.  go worker(ctx, "节点三"
  7.  time.Sleep(time.Second * 5) 
  8.  cancel() 
  9.  time.Sleep(time.Second * 5) 
  10.  fmt.Println("main goroutine 已结束"
  11.  
  12. func worker (ctx context.Context, node string) { 
  13.  for { 
  14.   select { 
  15.    case <-ctx.Done(): 
  16.     fmt.Println(node, "goroutine 已停止"
  17.     return 
  18.   default
  19.    fmt.Println(node, "goroutine 正在运行"
  20.    time.Sleep(time.Second
  21.   } 
  22.  } 

阅读上面这段代码,我们使用 go 关键字启动三个 worker goroutine,和上个示例一样,首先创建一个 context 树的根节点,使用第一个返回值 context 类型的子 ctx 跟踪每一个 worker goroutine,在 worker 中使用 for seclect 监控 <-ctx.Done() 判断子 goroutine 是否运行结束,最后通过调用第二个返回值 CancelFunc 类型的 cancel 给子 goroutine 发送取消指令,此时所有子 context 都会接收到取消指令,goroutine 结束运行。

04、上下文信息传递

我们在前面的示例中使用 WithCancel 函数,用作取消 context,除此之外,可用作取消 Context 的函数还有 WithDeadline 函数和 WithTimeout 函数,分别用于定时取消和超时取消,限于篇幅,本文不再赘述,感兴趣的读者可以查阅官方标准库文档。除了上述三个函数外,还有一个 WithValue 函数,它是用作上下文信息传递的一个函数。

在 Golang 语言中,Context 包还有一个重要的作用,就是用作上下文信息传递,接下来我们介绍一下如何使用 WithValue 函数传递上下文信息。

示例代码:

  1. func main () { 
  2.  ctx, cancel := context.WithCancel(context.Background()) 
  3.  // 传递上下文信息 
  4.  ctxValue := context.WithValue(ctx, "uid", 1) 
  5.  go func(ctx context.Context) { 
  6.   for { 
  7.    select { 
  8.     case <-ctx.Done(): 
  9.      fmt.Println(ctx.Value("uid"), "goroutine 已停止"
  10.      return 
  11.    default
  12.     fmt.Println("goroutine 正在运行"
  13.     time.Sleep(time.Second
  14.    } 
  15.   } 
  16.  }(ctxValue) 
  17.  time.Sleep(time.Second * 5) 
  18.  cancel() 
  19.  time.Sleep(time.Second * 5) 
  20.  fmt.Println("main goroutine 已结束"

阅读上面这段代码,我们使用 WithValue 函数给子 goroutine 传递上下文信息 uid。WithValue 函数接收三个参数,分别是 parent context,key 和 value。返回值是一个 context,我们可以在子 goroutine 中调用 Value 方法获取传递的上下文信息。

05、总结

本文我们简述了监控 goroutine 的几种方式,分别是 WaitGroup,chan + select 和 context。重点介绍了 context 的一些使用方式,分别是取消一个 goroutine,取消多个 goroutine 和传递上下文信息。关于定时取消和超时取消,感兴趣的读者可以参阅官方标准库文档。

原文地址:https://mp.weixin.qq.com/s?__biz=MzA4Mjc1NTMyOQ==&mid=2247484773&idx=1&sn=3e885c3f79165102b6bbfc4291e2b814&utm_source=tuicool&utm_medium=referral

延伸 · 阅读

精彩推荐
  • GolangGo语言实现自动填写古诗词实例代码

    Go语言实现自动填写古诗词实例代码

    这篇文章主要给大家介绍了关于Go语言实现自动填写古诗词的相关资料,这是最近在项目中遇到的一个需求,文中通过示例代码介绍的非常详细,需要的朋...

    FengY5862020-05-14
  • Golang深入浅析Go中三个点(...)用法

    深入浅析Go中三个点(...)用法

    这篇文章主要介绍了深入浅析Go中三个点(...)用法,需要的朋友可以参考下...

    踏雪无痕SS6472021-11-17
  • GolangGolang实现四种负载均衡的算法(随机,轮询等)

    Golang实现四种负载均衡的算法(随机,轮询等)

    本文介绍了示例介绍了Golang 负载均衡的四种实现,主要包括了随机,轮询,加权轮询负载,一致性hash,感兴趣的小伙伴们可以参考一下...

    Gundy_8442021-08-09
  • GolangGo语言range关键字循环时的坑

    Go语言range关键字循环时的坑

    今天小编就为大家分享一篇关于Go语言range关键字循环时的坑,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来...

    benben_20154202020-05-23
  • GolangGo语言基础单元测试与性能测试示例详解

    Go语言基础单元测试与性能测试示例详解

    这篇文章主要为大家介绍了Go语言基础单元测试与性能测试示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助祝大家多多进步...

    枫少文7812021-12-05
  • Golanggo语言获取系统盘符的方法

    go语言获取系统盘符的方法

    这篇文章主要介绍了go语言获取系统盘符的方法,涉及Go语言调用winapi获取系统硬件信息的技巧,具有一定参考借鉴价值,需要的朋友可以参考下 ...

    无尽海3862020-04-24
  • GolangGO语言字符串处理Strings包的函数使用示例讲解

    GO语言字符串处理Strings包的函数使用示例讲解

    这篇文章主要为大家介绍了GO语言字符串处理Strings包的函数使用示例讲解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加...

    Jeff的技术栈6882022-04-14
  • GolangGolang 语言极简类型转换库cast的使用详解

    Golang 语言极简类型转换库cast的使用详解

    本文我们通过 cast.ToString() 函数的使用,简单介绍了cast 的使用方法,除此之外,它还支持很多其他类型,在这没有多多介绍,对Golang 类型转换库 cast相关知...

    Golang语言开发栈6112021-12-02