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中semaphore(信号量)源码
Apr 03 Golang
Golang二维切片初始化的实现
Apr 08 Golang
golang interface判断为空nil的实现代码
Apr 24 Golang
go语言中切片与内存复制 memcpy 的实现操作
Apr 27 Golang
使用Golang的channel交叉打印两个数组的操作
Apr 29 Golang
解决golang post文件时Content-Type出现的问题
May 02 Golang
golang中字符串MD5生成方式总结
Jul 04 Golang
手把手教你导入Go语言第三方库
Aug 04 Golang
golang操作redis的客户端包有多个比如redigo、go-redis
Apr 14 Golang
golang生成并解析JSON
Apr 14 Golang
详解Go语言中配置文件使用与日志配置
Jun 01 Golang
Go结合Gin导出Mysql数据到Excel表格
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
Zend的AutoLoad机制介绍
2012/09/27 PHP
php统计文章排行示例
2014/03/04 PHP
php简单处理XML数据的方法示例
2017/05/19 PHP
yii gridview实现时间段筛选功能
2017/08/15 PHP
Laravel框架中VerifyCsrfToken报错问题的解决
2017/08/30 PHP
Laravel框架实现超简单的分页效果示例
2019/02/08 PHP
jQuery 技巧大全(新手入门篇)
2009/05/12 Javascript
基于jquery的多功能软键盘插件
2012/07/25 Javascript
JS实现图片横向滚动效果示例代码
2013/09/04 Javascript
javascript自启动函数的问题探讨
2013/10/05 Javascript
jQuery焦点图切换简易插件制作过程全纪录
2014/08/27 Javascript
Angular在一个页面中使用两个ng-app的方法(二)
2017/02/20 Javascript
基于Cookie常用操作以及属性介绍
2017/09/07 Javascript
vue学习笔记之v-if和v-show的区别
2017/09/20 Javascript
深入剖析Node.js cluster模块
2018/05/23 Javascript
mockjs+vue页面直接展示数据的方法
2018/12/19 Javascript
JavaScript中window和document用法详解
2020/07/28 Javascript
原生js实现表格循环滚动
2020/11/24 Javascript
[07:03]显微镜下的DOTA2第九期——430圣堂刺客杀戮秀
2014/06/20 DOTA
[40:03]RNG vs VG 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/17 DOTA
Python操作MongoDB数据库PyMongo库使用方法
2015/04/27 Python
python语言基本语句用法总结
2019/06/11 Python
一篇文章了解Python中常见的序列化操作
2019/06/20 Python
python如何实现代码检查
2019/06/28 Python
anaconda中更改python版本的方法步骤
2019/07/14 Python
Numpy数组array和矩阵matrix转换方法
2019/08/05 Python
Windows 下python3.8环境安装教程图文详解
2020/03/11 Python
怎么处理XML的中文问题
2015/03/26 面试题
小区文明倡议书
2014/05/16 职场文书
如何写求职信
2014/05/24 职场文书
交通局领导班子群众路线教育实践活动对照检查材料思想汇报
2014/10/09 职场文书
班主任先进事迹材料
2014/12/17 职场文书
学年个人总结范文
2015/03/05 职场文书
2015年大学生工作总结
2015/04/21 职场文书
《观潮》教学反思
2016/02/17 职场文书
《岳阳楼记》原文、译文赏析
2019/09/10 职场文书