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 02 Golang
go:垃圾回收GC触发条件详解
Apr 24 Golang
Go语言中的UTF-8实现
Apr 26 Golang
golang通过递归遍历生成树状结构的操作
Apr 28 Golang
golang 如何通过反射创建新对象
Apr 28 Golang
golang elasticsearch Client的使用详解
May 05 Golang
Golang实现AES对称加密的过程详解
May 20 Golang
K8s部署发布Golang应用程序的实现方法
Jul 16 Golang
手把手教你导入Go语言第三方库
Aug 04 Golang
Go语言并发编程 sync.Once
Oct 16 Golang
Go语言基础map用法及示例详解
Nov 17 Golang
浅谈GO中的Channel以及死锁的造成
Mar 18 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修正代码
2011/05/09 PHP
php中HTTP_REFERER函数用法实例
2014/11/21 PHP
apache php mysql开发环境安装教程
2016/07/28 PHP
laravel实现简单用户权限的示例代码
2019/05/28 PHP
PHP Cli 模式设置进程名称的方法
2019/06/12 PHP
JavaScript 获得选中文本内容的方法
2009/02/15 Javascript
Extjs显示从数据库取出时间转换JSON后的出现问题
2012/11/20 Javascript
最流行的Node.js精简型和全栈型开发框架介绍
2015/02/26 Javascript
在jQuery中使用$而避免跟其它库产生冲突的方法
2015/08/13 Javascript
谈谈target=_new和_blank的不同之处
2016/10/25 Javascript
bootstrap实现每隔5秒自动轮播效果
2016/12/20 Javascript
bootstrap paginator分页前后台用法示例
2017/06/17 Javascript
详解Angular Reactive Form 表单验证
2017/07/06 Javascript
React为 Vue 引入容器组件和展示组件的教程详解
2018/05/03 Javascript
nodejs中用npm初始化来创建package.json的实例讲解
2018/10/10 NodeJs
JS求解两数之和算法详解
2020/04/28 Javascript
js实现前端界面导航栏下拉列表
2020/08/27 Javascript
[47:50]Secret vs VP 2018国际邀请赛小组赛BO2 第二场 8.17
2018/08/20 DOTA
Python中对象迭代与反迭代的技巧总结
2016/09/17 Python
python用reduce和map把字符串转为数字的方法
2016/12/19 Python
Python通过OpenCV的findContours获取轮廓并切割实例
2018/01/05 Python
Python3 queue队列模块详细介绍
2018/01/05 Python
基于python 二维数组及画图的实例详解
2018/04/03 Python
python中subprocess批量执行linux命令
2018/04/27 Python
详解windows python3.7安装numpy问题的解决方法
2018/08/13 Python
python中round函数如何使用
2020/06/19 Python
Python+Selenium实现自动化的环境搭建的步骤(图文)
2020/09/01 Python
python利用递归方法实现求集合的幂集
2020/09/07 Python
python中判断数字是否为质数的实例讲解
2020/12/06 Python
在Ubuntu中安装并配置Pycharm教程的实现方法
2021/01/06 Python
移动端HTML5开发神器之vconsole详解
2020/12/15 HTML / CSS
印尼美容产品购物网站:PerfectBeauty.id
2017/12/01 全球购物
2014年语文教学工作总结
2014/12/17 职场文书
大学生党性分析材料
2014/12/19 职场文书
综合办公室主任岗位职责
2015/04/01 职场文书
使用Mysql计算地址的经纬度距离和实时位置信息
2022/04/29 MySQL