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语言-在mac下brew升级golang
Apr 25 Golang
浅谈Golang 嵌套 interface 的赋值问题
Apr 29 Golang
解决golang在import自己的包报错的问题
Apr 29 Golang
Golang中interface{}转为数组的操作
Apr 30 Golang
go类型转换及与C的类型转换方式
May 05 Golang
Golang 实现获取当前函数名称和文件行号等操作
May 08 Golang
Go语言实现Snowflake雪花算法
Jun 08 Golang
Go语言基础map用法及示例详解
Nov 17 Golang
golang操作redis的客户端包有多个比如redigo、go-redis
Apr 14 Golang
golang的文件创建及读写操作
Apr 14 Golang
Golang ort 中的sortInts 方法
Apr 24 Golang
基于Python实现西西成语接龙小助手
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 七大优势分析
2009/06/23 PHP
解析php入库和出库
2013/06/25 PHP
推荐10个提供免费PHP脚本下载的网站
2014/12/31 PHP
简单的无缝滚动程序-仅几行代码
2007/05/08 Javascript
Jquery 插件学习实例1 插件制作说明与tableUI优化
2010/04/02 Javascript
Jquery下:nth-child(an+b)的使用注意
2011/05/28 Javascript
最好用的省市二级联动 原生js实现你值得拥有
2013/09/22 Javascript
JS循环遍历JSON数据的方法
2014/07/08 Javascript
浅析js预加载/延迟加载
2014/09/25 Javascript
浅析node.js中close事件
2014/11/26 Javascript
jQuery控制DIV层实现由大到小,由远及近动画变化效果
2015/10/09 Javascript
BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
2016/12/01 Javascript
JS实现带导航城市列表以及输入搜索功能
2018/01/04 Javascript
原生JS实现的双色球功能示例
2018/02/02 Javascript
JavaScript学习笔记之图片库案例分析
2019/01/08 Javascript
vue中$refs, $emit, $on, $once, $off的使用详解
2019/05/26 Javascript
vue通过数据过滤实现表格合并
2020/11/30 Javascript
js针对图片加载失败的处理方法分析
2019/08/24 Javascript
下载安装setuptool和pip linux安装pip    
2014/01/24 Python
Python实现备份文件实例
2014/09/16 Python
在Python中使用sort()方法进行排序的简单教程
2015/05/21 Python
Python中struct模块对字节流/二进制流的操作教程
2017/01/21 Python
pytorch自定义二值化网络层方式
2020/01/07 Python
python实现用户名密码校验
2020/03/18 Python
Python文件操作基础流程解析
2020/03/19 Python
python plt可视化——打印特殊符号和制作图例代码
2020/04/17 Python
python 中关于pycharm选择运行环境的问题
2020/10/31 Python
HTML5 语音搜索只需一句代码
2013/01/03 HTML / CSS
英国一家集合了众多有才华设计师品牌的奢侈店:Wolf & Badger
2018/04/18 全球购物
Android面试题附答案
2014/12/08 面试题
运动会表扬稿大全
2014/01/16 职场文书
导航工程专业自荐信
2014/09/02 职场文书
毕业论文致谢部分怎么写
2015/05/14 职场文书
初二物理教学反思
2016/02/19 职场文书
Memcached介绍及php-memcache扩展安装
2021/04/01 PHP
Nginx速查手册及常见问题
2022/04/07 Servers