临近结课之余,本笔记旨在解决自己学习Go语言时留下的一个坑:既然Go语言是并发友好型语言,那么针对并发场景下的控制,Go语言提供了什么样优秀的解决关键字?
通过阅读Go圣经和相关图书,得出以下三种方案:
- Channel 管道
- WaitGroup 信号量
- Context 上下文
其中管道的实现方式最简单,常用于协程间的通信;其次信号量可作为上限限制最大并发数;而上下文则能管理庞大的树状协程,是 gRPC-g o上我们常常见到的ctx。
先说明协程并发控制的概念,我这里的理解是:让协程该停下时停下,做正确的事。
-
Channel 管道
管道操作有两种方式:第一种写入,第二种读出。
同时管道的存在形式也有两种方式:一是无缓冲,二是有缓冲。利用管道无缓冲的阻塞特性,我们可以实现对并发协程的控制。 -
WaitGroup 信号量
WaitGroup 对外提供了三个接口- Add(x int): 计数器+x(其数据结构维护一个 count 计数器,初始状态为0)
- Wait(): 等待数量+1
- Done(): 计数器-1
通过信号量增减等待实现并发控制。
-
Context 上下文
Context 对外提供四个方法- Deadline():返回一个 deadline
- Done():将 context 关闭,返回
- Err()
- Value()
Context仅仅是一个接口定义,可以衍生出不同类型的 context,如以下三种类型:
- cancelCtx:通过 WithCancel 方法创建
- timerCtx:通过 WithDeadline 和 WithTimeout 方法创建
- valueCtx:通过 WithValue 方法创建
三种 context 实例可互为父节点。