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原生库的中bytes.Buffer用法
Apr 25 Golang
golang中切片copy复制和等号复制的区别介绍
Apr 27 Golang
golang 实现两个结构体复制字段
Apr 28 Golang
go使用Gin框架利用阿里云实现短信验证码功能
Aug 04 Golang
简单聊聊Golang中defer预计算参数
Mar 25 Golang
Golang数据类型和相互转换
Apr 12 Golang
golang连接MySQl使用sqlx库
Apr 14 Golang
Go获取两个时区的时间差
Apr 20 Golang
Golang bufio详细讲解
Apr 21 Golang
Go web入门Go pongo2模板引擎
May 20 Golang
Go语言编译原理之变量捕获
Aug 05 Golang
GO中sync包自由控制并发示例详解
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
在apache下限制每个虚拟主机的并发数!!!!
2006/10/09 PHP
用PHP编写和读取XML的几种方式
2013/01/12 PHP
解析PHP中intval()等int转换时的意外异常情况
2013/06/21 PHP
php反射应用示例
2014/02/25 PHP
PHP版本如何选择?应该使用哪个版本?
2015/05/13 PHP
四个PHP非常实用的功能
2015/09/29 PHP
PHP+redis实现的限制抢购防止商品超发功能详解
2019/09/19 PHP
JavaScript 权威指南(第四版) 读书笔记
2009/08/11 Javascript
JsRender for object语法简介
2014/10/31 Javascript
JS实现给对象动态添加属性的方法
2017/01/05 Javascript
JavaScript ES6中export、import与export default的用法和区别
2017/03/14 Javascript
JS实现侧边栏鼠标经过弹出框+缓冲效果
2017/03/29 Javascript
小程序登录态管理的方法示例
2018/11/13 Javascript
jQuery访问json文件中数据的方法示例
2019/01/28 jQuery
对node通过fs模块判断文件是否是文件夹的实例讲解
2019/06/10 Javascript
Vue组件模板及组件互相引用代码实例
2020/03/11 Javascript
JavaScript实现通讯录功能
2020/12/27 Javascript
[02:12]2019完美世界全国高校联赛(春季赛)报名开启
2019/03/01 DOTA
python使用mysqldb连接数据库操作方法示例详解
2013/12/03 Python
Python的Flask框架及Nginx实现静态文件访问限制功能
2016/06/27 Python
Python简单操作sqlite3的方法示例
2017/03/22 Python
Django分页查询并返回jsons数据(中文乱码解决方法)
2018/08/02 Python
python中多个装饰器的执行顺序详解
2018/10/08 Python
python调用动态链接库的基本过程详解
2019/06/19 Python
使用python+whoosh实现全文检索
2019/12/09 Python
python中读入二维csv格式的表格方法详解(以元组/列表形式表示)
2020/04/24 Python
StubHub新加坡:购买和出售全球活动门票
2017/03/10 全球购物
英国地毯卖家:The Rug Seller
2019/07/18 全球购物
Java如何获得ResultSet的总行数
2016/09/03 面试题
教师师德考核自我评价
2014/09/13 职场文书
新郎接新娘保证书
2015/05/08 职场文书
劳动仲裁代理词范文
2015/05/25 职场文书
小平小道观后感
2015/06/09 职场文书
如何写好开幕词?
2019/06/24 职场文书
vue-cli4.5.x快速搭建项目
2021/05/30 Vue.js
pycharm部署django项目到云服务器的详细流程
2021/06/29 Python