Golang 语言控制并发 Goroutine的方法


Posted in Golang onJune 30, 2021

goroutine 是 Go语言中的轻量级线程实现,由 Go 运行时(runtime)管理。Go 程序会智能地将 goroutine 中的任务合理地分配给每个 CPU。

01介绍

Golang 语言的优势之一是天生支持并发,我们在 Golang 语言开发中,通常使用的并发控制方式主要有 Channel,WaitGroup 和 Context,本文我们主要介绍一下 Golang 语言中并发控制的这三种方式怎么使用?关于它们各自的详细介绍在之前的文章已经介绍过,感兴趣的读者朋友们可以按需翻阅。

02Channel

在 Golang 语言中,Channel 不仅可以用于协程之间通信,还可以使用 Channel 控制子协程,而且使用 Channel 实现并发控制比较简单,比如以下示例,我们在 Golang 应用程序中启动两个协程,分别是主协程和子协程,主协程需要等待子协程运行结束后再退出程序。

示例代码:

func main () { 
 done := make(chan struct{}) 
 go func() { 
  fmt.Println("goroutine run over") 
  done <- struct{}{} 
 }() 
 <- done 
 fmt.Println("main goroutine run over") 
}

阅读上面这段代码,我们在子 goroutine 运行结束后,通过 Channel 通知主 goroutine 退出程序,实际上也可以反过来处理,主 goroutine 通知子 goroutine 退出程序,主 goroutine 向 channel 中发送数据,子 goroutine 等待接收 channel 中的数据。

03sync.WaitGroup

如果在 Golang 应用程序中,需要让主 goroutine 等待多个 goroutine 都运行结束后再退出程序,我们应该怎么实现呢?是的,同样可以使用 Channel 实现,但是,有一个更优雅的实现方式,那就是 WaitGroup,顾名思义,WaitGroup 就是等待一组 goroutine 运行结束。

示例代码:

func main () { 
 wg := sync.WaitGroup{} 
 wg.Add(10) 
 for i := 0; i < 10; i++ { 
  go func(id int) { 
   fmt.Println(id, "运行结束") 
   wg.Done() 
  }(i) 
 } 
 wg.Wait() 
 fmt.Println("main goroutine run over") 
}

阅读上面这段代码,我们启动 10 个子 goroutine,主 goroutine 需要等待 10 个子 goroutine 都运行结束后再退出程序,我们使用的是 WaitGroup,它有三个方法,分别是 Add、Done 和 Wait,实际上 WaitGroup 维护了一个计数器,这三个方法都是围绕这个计数器工作,Add 用于设置计数器的数值,Done 用于扣减计数器的数值,Wait 在计数器数值为 0 之前一直阻塞。关于 WaitGroup 的源码解读,在之前的文章中已介绍过,限于篇幅,这里就不再赘述。

04Context

Channel 和 WaitGroup 通常用于父子两个层级的 goroutine 的应用程序的并发控制中,如果在 Golang 应用程序中,子协程继续派生出协程,我们应该怎么控制呢?这种多级 goroutine 的应用程序,我们可以使用 Context 实现并发控制。

示例代码:

func main() { 
 ctx, cancel := context.WithCancel(context.Background()) 
 go firstCtx(ctx) 
 time.Sleep(5 * time.Second) 
 fmt.Println("stop all sub goroutine") 
 cancel() 
 time.Sleep(5 * time.Second) 
} 
 
func firstCtx(ctx context.Context) { 
 go secondCtx(ctx) 
 for { 
  select { 
  case <-ctx.Done(): 
   fmt.Println("first done") 
   return 
  default: 
   fmt.Println("first running") 
   time.Sleep(2 * time.Second) 
  } 
 } 
} 
 
func secondCtx(ctx context.Context) { 
 for { 
  select { 
  case <-ctx.Done(): 
   fmt.Println("second done") 
   return 
  default: 
   fmt.Println("second running") 
   time.Sleep(2 * time.Second) 
  } 
 } 
}

阅读上面这段代码,在子协程 firstCtx 启动子协程 secondCtx,主 goroutine 创建 context,并把 context 传递到所有子协程,然后主 goroutine 通过调用 cancle 停掉所有子协程。

05总结

本文我们介绍了不同场景中分别适合哪种控制并发 goroutine 的方式,其中,channel 适合控制少量 并发 goroutine,WaitGroup 适合控制一组并发 goroutine,而 context 适合控制多级并发 goroutine。

到此这篇关于Golang 语言控制并发 Goroutine的方法的文章就介绍到这了,更多相关Golang并发控制Goroutine内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Golang 相关文章推荐
Go语言-为什么返回值为接口类型,却返回结构体
Apr 24 Golang
Golang 正则匹配效率详解
Apr 25 Golang
解决golang post文件时Content-Type出现的问题
May 02 Golang
Golang: 内建容器的用法
May 05 Golang
Golang 编译成DLL文件的操作
May 06 Golang
Golang中异常处理机制详解
Jun 08 Golang
Go语言空白表示符_的实例用法
Jul 04 Golang
如何利用golang运用mysql数据库
Mar 13 Golang
Go并发4种方法简明讲解
Apr 06 Golang
GO语言字符串处理函数之处理Strings包
Apr 14 Golang
在ubuntu下安装go开发环境的全过程
Aug 05 Golang
Golang的继承模拟实例
Jun 30 #Golang
go select编译期的优化处理逻辑使用场景分析
Go 语言下基于Redis分布式锁的实现方式
Jun 28 #Golang
go语言使用Casbin实现角色的权限控制
Go语言设计模式之结构型模式
浅谈Go语言多态的实现与interface使用
Jun 16 #Golang
再次探讨go实现无限 buffer 的 channel方法
Jun 13 #Golang
You might like
PHP数据缓存技术
2007/02/14 PHP
PHP 上传文件的方法(类)
2009/07/30 PHP
兼容ie6浏览器的php下载文件代码分享
2014/07/14 PHP
PHP遍历数组的三种方法及效率对比分析
2015/02/12 PHP
PHP读取CSV大文件导入数据库的实例
2017/07/24 PHP
PHP实现动态删除XML数据的方法示例
2018/03/30 PHP
ThinkPHP框架获取最后一次执行SQL语句及变量调试简单操作示例
2018/06/13 PHP
js 验证密码强弱的小例子
2013/03/21 Javascript
js 数组操作之pop,push,unshift,splice,shift
2014/01/29 Javascript
node.js中的http.response.getHeader方法使用说明
2014/12/14 Javascript
JavaScript子窗口调用父窗口变量和函数的方法
2015/10/09 Javascript
javascript中的altKey 和 Event属性大全
2015/11/06 Javascript
Javascript表单特效之十大常用原理性样例代码大总结
2016/07/12 Javascript
javascript弹出带文字信息的提示框效果
2016/07/19 Javascript
jquery pagination插件动态分页实例(Bootstrap分页)
2016/12/23 Javascript
浅谈函数调用的不同方式,以及this的指向
2017/09/17 Javascript
vue.js实现备忘录demo
2019/06/26 Javascript
原生JS实现天气预报
2020/06/16 Javascript
基于js实现判断浏览器类型代码实例
2020/07/17 Javascript
Python实现读取Properties配置文件的方法
2018/03/29 Python
Selenium定时刷新网页的实现代码
2018/10/31 Python
基于python生成器封装的协程类
2019/03/20 Python
Python空间数据处理之GDAL读写遥感图像
2019/08/01 Python
图文详解Django使用Pycharm连接MySQL数据库
2019/08/09 Python
Django模板语言 Tags使用详解
2019/09/09 Python
python中time.ctime()实例用法
2021/02/03 Python
英国百安居装饰建材网上超市:B&Q
2016/09/13 全球购物
印尼在线精品店:Berrybenka.com
2016/10/22 全球购物
印尼第一大家居、生活和家具电子商务:Ruparupa
2019/11/25 全球购物
北京华建集团SQL面试题
2014/06/03 面试题
表彰大会主持词
2014/03/26 职场文书
实习介绍信范文
2015/05/05 职场文书
百日宴上的祝酒词
2015/08/10 职场文书
mysql主从复制的实现步骤
2021/10/24 MySQL
quickjs 封装 JavaScript 沙箱详情
2021/11/02 Javascript
React Fragment介绍与使用详解
2021/11/11 Javascript